diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 6782a34..027bd40 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index e9294bd..454d64a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,4 +38,4 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2' implementation 'com.android.support:support-v4:27.1.1' -} \ No newline at end of file +} diff --git a/app/src/main/java/de/sebse/fuplanner/MainActivity.java b/app/src/main/java/de/sebse/fuplanner/MainActivity.java index c1a5e72..eccdffa 100644 --- a/app/src/main/java/de/sebse/fuplanner/MainActivity.java +++ b/app/src/main/java/de/sebse/fuplanner/MainActivity.java @@ -6,7 +6,6 @@ import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.os.Bundle; import android.support.annotation.NonNull; -import android.util.Log; import android.view.View; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; @@ -18,6 +17,7 @@ import android.view.Menu; import android.view.MenuItem; import de.sebse.fuplanner.fragments.LoginFragment; +import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment; import de.sebse.fuplanner.fragments.ModulesFragment; import de.sebse.fuplanner.fragments.StartupFragment; import de.sebse.fuplanner.services.GoogleAuth.ConnectedListener; @@ -27,7 +27,7 @@ import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth; import de.sebse.fuplanner.services.KVV.KVV; import de.sebse.fuplanner.services.KVV.LoginToken; import de.sebse.fuplanner.services.KVV.Modules; -import de.sebse.fuplanner.tools.activity.Logger; +import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.network.NetworkCallback; import de.sebse.fuplanner.tools.network.NetworkError; import de.sebse.fuplanner.tools.network.NetworkErrorCallback; @@ -35,13 +35,13 @@ import de.sebse.fuplanner.tools.network.NetworkErrorCallback; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, LoginFragment.OnLoginFragmentInteractionListener, - StartupFragment.OnStartupFragmentInteractionListener, - ModulesFragment.OnModulesFragmentInteractionListener { + ModulesFragment.OnModulesFragmentInteractionListener, + ModDetailFragment.OnModuleDetailFragmentInteractionListener { FragmentManager fragmentManager; private GoogleAuth mGoogleAuth; private KVV mKVV; - private Logger log = new Logger("MainAct"); + private Logger log = new Logger(this); @Override protected void onCreate(Bundle savedInstanceState) { @@ -94,6 +94,7 @@ public class MainActivity extends AppCompatActivity }, new NetworkErrorCallback() { @Override public void onError(NetworkError error) { + log.e(error); MainActivity.this.getKVV().endUpdate(); changeLoginState(null); } @@ -142,21 +143,30 @@ public class MainActivity extends AppCompatActivity // Handle navigation view item clicks here. int id = item.getItemId(); - if (id == R.id.nav_schedule) { + switch (id) { + case R.id.nav_modules: + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.replace(R.id.fragcontainer, ModulesFragment.newInstance()); + fragmentTransaction.commit(); + break; + case R.id.nav_schedule: - } else if (id == R.id.nav_share) { + break; + case R.id.nav_share: - } else if (id == R.id.nav_logout) { - this.getKVV().logout(); - this.getGoogleAuth().getLoginState(new CredentialsListener() { - @Override - public void onCredentials(Credentials credentials) { - if (credentials != null) { - MainActivity.this.getGoogleAuth().deleteLoginState(credentials.getUsername(), credentials.getPassword()); + break; + case R.id.nav_logout: + this.getKVV().logout(); + this.getGoogleAuth().getLoginState(new CredentialsListener() { + @Override + public void onCredentials(Credentials credentials) { + if (credentials != null) { + MainActivity.this.getGoogleAuth().deleteLoginState(credentials.getUsername(), credentials.getPassword()); + } + MainActivity.this.changeLoginState(null); } - MainActivity.this.changeLoginState(null); - } - }); + }); + break; } DrawerLayout drawer = findViewById(R.id.drawer_layout); @@ -227,7 +237,7 @@ public class MainActivity extends AppCompatActivity getKVV().getModuleList(new NetworkCallback() { @Override public void onResponse(@NonNull Modules success) { - log.d("Modules.get "+success.size()); + log.d("Modules.get", success.size()); //SubMenu moduleMenu = navigationView.getMenu().findItem(R.id.nav_modules).getSubMenu(); int i = 0; for (Modules.Module module: success) { @@ -248,7 +258,7 @@ public class MainActivity extends AppCompatActivity }, new NetworkErrorCallback() { @Override public void onError(NetworkError error) { - log.d("Modules.error "+error.toString()); + log.d("Modules.error", error); } }); } @@ -269,18 +279,13 @@ public class MainActivity extends AppCompatActivity changeLoginState(credentials); } - @Override - public void onStartupFragmentInteraction(Uri uri) { - - } - @Override public void onModulesFragmentInteraction(final int itemPosition) { - Log.d("MainAct", "Item clicked "+itemPosition); + log.d("Item clicked", itemPosition); getKVV().getModuleList(new NetworkCallback() { @Override public void onResponse(@NonNull Modules success) { - Log.d("MainAct", success.get(itemPosition).title); + log.d(success.get(itemPosition).title); } }, new NetworkErrorCallback() { @Override @@ -288,5 +293,14 @@ public class MainActivity extends AppCompatActivity // TODO } }); + + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.replace(R.id.fragcontainer, ModDetailFragment.newInstance(itemPosition)); + fragmentTransaction.commit(); + } + + @Override + public void onModuleDetailFragmentInteraction(Uri uri) { + log.d("Cooles ding"); } } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java index 867b2ce..431ae14 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java @@ -17,6 +17,7 @@ import de.sebse.fuplanner.services.GoogleAuth.Credentials; import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth; import de.sebse.fuplanner.services.KVV.KVV; import de.sebse.fuplanner.services.KVV.LoginToken; +import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.network.NetworkCallback; import de.sebse.fuplanner.tools.network.NetworkError; import de.sebse.fuplanner.tools.network.NetworkErrorCallback; @@ -36,6 +37,7 @@ public class LoginFragment extends Fragment { // TODO: Rename and change types of parameters private OnLoginFragmentInteractionListener mListener; + private Logger log = new Logger(this); public LoginFragment() { // Required empty public constructor @@ -83,7 +85,7 @@ public class LoginFragment extends Fragment { if (input_usr != null) { if (input_pwd != null) { if (LoginFragment.this.getActivity() == null) { - Log.e("KVVLogin", "Login fragment has no activity!"); + log.e("Login fragment has no activity!"); return; } final String username = input_usr.getText().toString(); @@ -94,7 +96,7 @@ public class LoginFragment extends Fragment { @Override public void onResponse(@NonNull LoginToken success) { progressDialog.dismiss(); - Log.d("KVVLogin", success.toString()); + log.d("success", success.toString()); gauth.setLoginState(username, password); if (LoginFragment.this.mListener != null) { Credentials cred = new Credentials(username, password); @@ -105,7 +107,7 @@ public class LoginFragment extends Fragment { @Override public void onError(NetworkError error) { progressDialog.dismiss(); - Log.e("KVVLoginError", error.getCode()+""); + log.e("error", error); } }); } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/StartupFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/StartupFragment.java index 1ef38b8..5bfc421 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/StartupFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/StartupFragment.java @@ -3,6 +3,7 @@ package de.sebse.fuplanner.fragments; import android.content.Context; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; @@ -19,12 +20,6 @@ import de.sebse.fuplanner.R; * create an instance of this fragment. */ public class StartupFragment extends Fragment { - // TODO: Rename parameter arguments, choose names that match - // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER - - // TODO: Rename and change types of parameters - - private OnStartupFragmentInteractionListener mListener; public StartupFragment() { // Required empty public constructor @@ -36,7 +31,6 @@ public class StartupFragment extends Fragment { * * @return A new instance of fragment StartupFragment. */ - // TODO: Rename and change types and number of parameters public static StartupFragment newInstance() { StartupFragment fragment = new StartupFragment(); Bundle args = new Bundle(); @@ -50,42 +44,9 @@ public class StartupFragment extends Fragment { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - View v = inflater.inflate(R.layout.fragment_startup, container, false); - return v; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnStartupFragmentInteractionListener) { - mListener = (OnStartupFragmentInteractionListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnStartupFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - *

- * See the Android Training lesson Communicating with Other Fragments for more information. - */ - public interface OnStartupFragmentInteractionListener { - // TODO: Update argument type and name - void onStartupFragmentInteraction(Uri uri); + return inflater.inflate(R.layout.fragment_startup, container, false); } } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAdapter.java new file mode 100644 index 0000000..c5f2cfd --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAdapter.java @@ -0,0 +1,38 @@ +package de.sebse.fuplanner.fragments.moddetails; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; + +class ModDetailAdapter extends FragmentPagerAdapter { + public ModDetailAdapter(FragmentManager fm) { + super(fm); + } + + + // Returns total number of pages + @Override + public int getCount() { + return 2; + } + + // Returns the fragment to display for that page + @Override + public Fragment getItem(int position) { + switch (position) { + case 0: // Fragment # 0 - This will show FirstFragment + return ModDetailOverviewFragment.newInstance("1", "Page # 1"); + case 1: // Fragment # 0 - This will show FirstFragment different title + return ModDetailAnnounceFragment.newInstance("2", "Page # 2"); + default: + return null; + } + } + + // Returns the page title for the top indicator + @Override + public CharSequence getPageTitle(int position) { + return "Page " + position; + } + +} diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java new file mode 100644 index 0000000..e6efa2a --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java @@ -0,0 +1,66 @@ +package de.sebse.fuplanner.fragments.moddetails; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import de.sebse.fuplanner.R; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link ModDetailAnnounceFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class ModDetailAnnounceFragment extends Fragment { + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + private static final String ARG_PARAM1 = "param1"; + private static final String ARG_PARAM2 = "param2"; + + // TODO: Rename and change types of parameters + private String mParam1; + private String mParam2; + + + public ModDetailAnnounceFragment() { + // Required empty public constructor + } + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param param1 Parameter 1. + * @param param2 Parameter 2. + * @return A new instance of fragment ModDetailAnnounceFragment. + */ + // TODO: Rename and change types and number of parameters + public static ModDetailAnnounceFragment newInstance(String param1, String param2) { + ModDetailAnnounceFragment fragment = new ModDetailAnnounceFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PARAM1, param1); + args.putString(ARG_PARAM2, param2); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_mod_detail_announce, container, false); + } + +} diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java new file mode 100644 index 0000000..c2d4d49 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java @@ -0,0 +1,112 @@ +package de.sebse.fuplanner.fragments.moddetails; + +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import de.sebse.fuplanner.R; + +/** + * A simple {@link Fragment} subclass. + * Activities that contain this fragment must implement the + * {@link OnModuleDetailFragmentInteractionListener} interface + * to handle interaction events. + * Use the {@link ModDetailFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class ModDetailFragment extends Fragment { + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + private static final String ARG_POSITION = "itemPosition"; + + // TODO: Rename and change types of parameters + private int mItemPos; + + private OnModuleDetailFragmentInteractionListener mListener; + private ModDetailAdapter adapterViewPager; + + public ModDetailFragment() { + // Required empty public constructor + } + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param itemPosition Item position in module list. + * @return A new instance of fragment ModDetailFragment. + */ + // TODO: Rename and change types and number of parameters + public static Fragment newInstance(int itemPosition) { + ModDetailFragment fragment = new ModDetailFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_POSITION, itemPosition); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mItemPos = getArguments().getInt(ARG_POSITION); + } + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View v = inflater.inflate(R.layout.fragment_mod_detail, container, false); + + ViewPager vpPager = (ViewPager) v.findViewById(R.id.vpPager); + adapterViewPager = new ModDetailAdapter(getFragmentManager()); + vpPager.setAdapter(adapterViewPager); + return v; + } + + // TODO: Rename method, update argument and hook method into UI event + public void onButtonPressed(Uri uri) { + if (mListener != null) { + mListener.onModuleDetailFragmentInteraction(uri); + } + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnModuleDetailFragmentInteractionListener) { + mListener = (OnModuleDetailFragmentInteractionListener) context; + } else { + throw new RuntimeException(context.toString() + + " must implement OnModuleDetailFragmentInteractionListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + *

+ * See the Android Training lesson Communicating with Other Fragments for more information. + */ + public interface OnModuleDetailFragmentInteractionListener { + // TODO: Update argument type and name + void onModuleDetailFragmentInteraction(Uri uri); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java new file mode 100644 index 0000000..ff4aaf5 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java @@ -0,0 +1,66 @@ +package de.sebse.fuplanner.fragments.moddetails; + + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import de.sebse.fuplanner.R; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link ModDetailOverviewFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class ModDetailOverviewFragment extends Fragment { + // TODO: Rename parameter arguments, choose names that match + // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER + private static final String ARG_PARAM1 = "param1"; + private static final String ARG_PARAM2 = "param2"; + + // TODO: Rename and change types of parameters + private String mParam1; + private String mParam2; + + + public ModDetailOverviewFragment() { + // Required empty public constructor + } + + /** + * Use this factory method to create a new instance of + * this fragment using the provided parameters. + * + * @param param1 Parameter 1. + * @param param2 Parameter 2. + * @return A new instance of fragment ModDetailOverviewFragment. + */ + // TODO: Rename and change types and number of parameters + public static ModDetailOverviewFragment newInstance(String param1, String param2) { + ModDetailOverviewFragment fragment = new ModDetailOverviewFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PARAM1, param1); + args.putString(ARG_PARAM2, param2); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_mod_detail_overview, container, false); + } + +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/MensaPlan.java b/app/src/main/java/de/sebse/fuplanner/services/MensaPlan.java index 0709676..ae852a6 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/MensaPlan.java +++ b/app/src/main/java/de/sebse/fuplanner/services/MensaPlan.java @@ -4,13 +4,11 @@ import android.content.Context; import android.util.Log; import com.android.volley.AuthFailureError; -import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.VolleyLog; -import com.android.volley.toolbox.HttpHeaderParser; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; diff --git a/app/src/main/java/de/sebse/fuplanner/tools/activity/Logger.java b/app/src/main/java/de/sebse/fuplanner/tools/activity/Logger.java deleted file mode 100644 index eed1fc9..0000000 --- a/app/src/main/java/de/sebse/fuplanner/tools/activity/Logger.java +++ /dev/null @@ -1,41 +0,0 @@ -package de.sebse.fuplanner.tools.activity; - -import android.support.v7.app.AppCompatActivity; -import android.util.Log; - -/** - * Created by sebastian on 19.04.18. - */ - -public class Logger { - private final String tag; - - public Logger(String tag) { - super(); - this.tag = tag; - } - - public void d(String text) { - Log.d(tag, text); - } - - public void d(boolean text) { - Log.d(tag, String.valueOf(text)); - } - - public void d(int text) { - Log.d(tag, String.valueOf(text)); - } - - public void e(String text) { - Log.e(tag, text); - } - - public void e(boolean text) { - Log.e(tag, String.valueOf(text)); - } - - public void e(int text) { - Log.e(tag, String.valueOf(text)); - } -} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/logging/Logger.java b/app/src/main/java/de/sebse/fuplanner/tools/logging/Logger.java new file mode 100644 index 0000000..cf5f08e --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/logging/Logger.java @@ -0,0 +1,29 @@ +package de.sebse.fuplanner.tools.logging; + +import android.util.Log; + +public class Logger { + private final String tag; + + public Logger(Object object) { + this.tag = object.getClass().getSimpleName(); + } + + public void d(Object... msg) { + Log.d(tag, concat(msg)); + } + + public void e(Object... msg) { + Log.e(tag, concat(msg)); + } + + private String concat(Object[] msg) { + StringBuilder string = new StringBuilder(); + for (Object arg: msg) + if (arg != null) + string.append(arg.toString()).append(" "); + else + string.append("null "); + return string.toString(); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/network/BetterHurlStack.java b/app/src/main/java/de/sebse/fuplanner/tools/network/BetterHurlStack.java index 8f1badf..d832715 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/network/BetterHurlStack.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/network/BetterHurlStack.java @@ -78,7 +78,7 @@ public class BetterHurlStack extends HurlStack { public HttpResponse performRequest(Request request, Map additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); - HashMap map = new HashMap(); + HashMap map = new HashMap<>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders); if (mUrlRewriter != null) { diff --git a/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java b/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java index 418d7be..cf439c1 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java @@ -5,9 +5,11 @@ import android.support.annotation.Nullable; import android.util.Log; import com.android.volley.AuthFailureError; +import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; +import com.android.volley.TimeoutError; import com.android.volley.VolleyError; import com.android.volley.toolbox.Volley; @@ -16,6 +18,8 @@ import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; +import de.sebse.fuplanner.tools.logging.Logger; + /** * Created by sebastian on 24.10.17. */ @@ -23,6 +27,7 @@ import java.util.Map; public class HTTPService { protected RequestQueue requestQueue; private boolean followRedirects; + protected Logger log = new Logger(this); public HTTPService(Context context) { this(context, false); @@ -38,10 +43,17 @@ public class HTTPService { @Override public void deliverError(VolleyError error) { if (error == null) { - super.deliverError(null); + super.deliverError(new VolleyError(new NetworkResponse(500, null, null, true, 0))); + } else if (error.networkResponse == null) { + int statusCode; + if (error instanceof TimeoutError) + statusCode = 408; + else + statusCode = 500; + super.deliverError(new VolleyError(new NetworkResponse(statusCode, null, null, true, error.getNetworkTimeMs()))); } else { final int status = error.networkResponse.statusCode; - if (status == 302 && !followRedirects) { + if (status == 302) { super.deliverResponse(new Result(null, error.networkResponse.headers)); } else { super.deliverError(error); @@ -87,7 +99,7 @@ public class HTTPService { sb.append('&'); } try { - Log.e("Superissimo", e.getKey()+"|||"+e.getValue()); + //Log.e("Superissimo", e.getKey()+"|||"+e.getValue()); sb.append(URLEncoder.encode(e.getKey(), "UTF-8")).append('=').append(URLEncoder.encode(e.getValue(), "UTF-8")); } catch (UnsupportedEncodingException ignored) { } @@ -102,11 +114,22 @@ public class HTTPService { @Override public void deliverError(VolleyError error) { - final int status = error.networkResponse.statusCode; - if (status == 302) { - super.deliverResponse(new Result(null, error.networkResponse.headers)); + if (error == null) { + super.deliverError(new VolleyError(new NetworkResponse(500, null, null, true, 0))); + } else if (error.networkResponse == null) { + int statusCode; + if (error instanceof TimeoutError) + statusCode = 408; + else + statusCode = 500; + super.deliverError(new VolleyError(new NetworkResponse(statusCode, null, null, true, error.getNetworkTimeMs()))); } else { - super.deliverError(error); + final int status = error.networkResponse.statusCode; + if (status == 302) { + super.deliverResponse(new Result(null, error.networkResponse.headers)); + } else { + super.deliverError(error); + } } } @@ -130,7 +153,7 @@ public class HTTPService { requestQueue.add(request); } - public static void largeLog(String tag, String content) { + private static void largeLog(String tag, String content) { if (content==null) { Log.d(tag, "null"); } else if (content.length() > 4000) { diff --git a/app/src/main/java/de/sebse/fuplanner/tools/network/HttpRequest.java b/app/src/main/java/de/sebse/fuplanner/tools/network/HttpRequest.java index 5a298e8..3e53f97 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/network/HttpRequest.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/network/HttpRequest.java @@ -1,5 +1,6 @@ package de.sebse.fuplanner.tools.network; +import com.android.volley.DefaultRetryPolicy; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; @@ -12,12 +13,17 @@ import java.io.UnsupportedEncodingException; */ public class HttpRequest extends Request { + private static final int MY_SOCKET_TIMEOUT_MS = 15000; private final Response.Listener mListener; public HttpRequest(int method, String url, Response.Listener listener, Response.ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; + this.setRetryPolicy(new DefaultRetryPolicy( + MY_SOCKET_TIMEOUT_MS, + DefaultRetryPolicy.DEFAULT_MAX_RETRIES, + DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); } @Override diff --git a/app/src/main/res/layout/fragment_mod_detail.xml b/app/src/main/res/layout/fragment_mod_detail.xml new file mode 100644 index 0000000..2ee206d --- /dev/null +++ b/app/src/main/res/layout/fragment_mod_detail.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_mod_detail_announce.xml b/app/src/main/res/layout/fragment_mod_detail_announce.xml new file mode 100644 index 0000000..6fe1860 --- /dev/null +++ b/app/src/main/res/layout/fragment_mod_detail_announce.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_mod_detail_overview.xml b/app/src/main/res/layout/fragment_mod_detail_overview.xml new file mode 100644 index 0000000..6a9e612 --- /dev/null +++ b/app/src/main/res/layout/fragment_mod_detail_overview.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_modules_list.xml b/app/src/main/res/layout/fragment_modules_list.xml index 807729f..bd04f91 100644 --- a/app/src/main/res/layout/fragment_modules_list.xml +++ b/app/src/main/res/layout/fragment_modules_list.xml @@ -8,6 +8,6 @@ android:layout_height="match_parent" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" - app:layoutManager="LinearLayoutManager" + app:layoutManager="android.support.v7.widget.LinearLayoutManager" tools:context="de.sebse.fuplanner.fragments.ModulesFragment" tools:listitem="@layout/fragment_modules" /> diff --git a/docs/GoogleAuth.java b/docs/GoogleAuth.java deleted file mode 100644 index a03fe89..0000000 --- a/docs/GoogleAuth.java +++ /dev/null @@ -1,301 +0,0 @@ -package de.sebse.fuplanner.services.GoogleAuth; - -import android.content.Intent; -import android.content.IntentSender; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; -import android.util.Log; -import android.widget.Toast; - -import com.google.android.gms.auth.api.Auth; -import com.google.android.gms.auth.api.credentials.Credential; -import com.google.android.gms.auth.api.credentials.CredentialRequest; -import com.google.android.gms.auth.api.credentials.CredentialRequestResponse; -import com.google.android.gms.auth.api.credentials.CredentialRequestResult; -import com.google.android.gms.auth.api.credentials.CredentialsClient; -import com.google.android.gms.auth.api.credentials.CredentialsOptions; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GoogleApiAvailability; -import com.google.android.gms.common.api.ApiException; -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.ResolvableApiException; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Status; -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.android.gms.tasks.Task; - -import static android.app.Activity.RESULT_OK; - -/** - * Created by Sebastian on 06.11.2017. - */ - -public class GoogleAuth { - // https://developers.google.com/identity/smartlock-passwords/android/retrieve-credentials - - private static final String TAG = "GoogleAuth"; - private final FragmentActivity activity; - private CredentialsClient mCredentialsClient; - private boolean mIsResolving; - - public GoogleAuth(FragmentActivity activity) { - this.activity = activity; - } - - public void connect(final ConnectedListener listener) { - if (!this.isAvailable()) { - Log.d(TAG, "STATUS: Google auth not available!"); - listener.connected(); - return; - } - this.mCredentialsClient = getClient(new GoogleApiClient.ConnectionCallbacks() { - @Override - public void onConnected(@Nullable Bundle bundle) { - listener.connected(); - } - - @Override - public void onConnectionSuspended(int i) { - } - }, new GoogleApiClient.OnConnectionFailedListener() { - @Override - public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { - - } - }); - } - - - - - public void getLoginState(final CredentialsListener credentialsListener) { - if (!this.isAvailable()) { - Log.d(TAG, "STATUS: Google auth not available!"); - credentialsListener.onCredentials(null); - return; - } - CredentialRequest request = new CredentialRequest.Builder() - .setPasswordLoginSupported(true) - .build(); - - - mCredentialsClient.request(request).addOnCompleteListener( - new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - - if (task.isSuccessful()) { - // Successfully read the credential without any user interaction, this - // means there was only a single credential and the user has auto - // sign-in enabled. - Credential credential = task.getResult().getCredential(); - credentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword())); - return; - } - - Exception e = task.getException(); - if (e instanceof ResolvableApiException) { - // This is most likely the case where the user has multiple saved - // credentials and needs to pick one. This requires showing UI to - // resolve the read request. - ResolvableApiException rae = (ResolvableApiException) e; - resolveResult(rae, RequestCode.RC_READ); - return; - } - - if (e instanceof ApiException) { - ApiException ae = (ApiException) e; - if (ae.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) { - // This means only a hint is available, but we are handling that - // elsewhere so no need to act here. - } else { - Log.w(TAG, "Unexpected status code: " + ae.getStatusCode()); - } - } - } - }); - - - - - - - /*Auth.CredentialsApi.request(this.mCredentialsClient, mCredentialRequest).setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull CredentialRequestResult credentialRequestResult) { - if (credentialRequestResult.getStatus().isSuccess()) { - // See "Handle successful credential requests" - Credential credential = credentialRequestResult.getCredential(); - credentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword())); - } else { - // See "Handle unsuccessful and incomplete credential requests" - credentialsListener.onCredentials(null); - } - } - } - );*/ - } - - public void setLoginState(String username, String password) { - if (!this.isAvailable()) { - Log.d(TAG, "STATUS: Google auth not available!"); - Toast.makeText(activity, "Google auth not available!", Toast.LENGTH_SHORT).show(); - return; - } - Credential credential = new Credential.Builder(username) - .setPassword(password) - .build(); - mCredentialsClient.save(credential).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - showToast("Credential saved."); - return; - } - - Exception e = task.getException(); - if (e instanceof ResolvableApiException) { - // The first time a credential is saved, the user is shown UI - // to confirm the action. This requires resolution. - ResolvableApiException rae = (ResolvableApiException) e; - resolveResult(rae, RequestCode.RC_SAVE); - } else { - // Save failure cannot be resolved. - Log.w(TAG, "Save failed.", e); - showToast("Credential Save Failed"); - } - } - }); - - - - - /*Auth.CredentialsApi.save(mCredentialsClient, credential).setResultCallback( - new ResultCallback() { - @Override - public void onResult(@NonNull Status status) { - if (status.isSuccess()) { - Log.d(TAG, "SAVE: OK"); - Toast.makeText(activity, "Credentials saved", Toast.LENGTH_SHORT).show(); - } else { - Log.d(TAG, String.valueOf(status.hasResolution())); - Log.d(TAG, String.valueOf(status.getStatus())); - if (status.hasResolution()) { - // Try to resolve the save request. This will prompt the user if - // the credential is new. - try { - status.startResolutionForResult(activity, RC_SAVE); - } catch (IntentSender.SendIntentException e) { - // Could not resolve the request - Log.e(TAG, "STATUS: Failed to send resolution.", e); - Toast.makeText(activity, "Save failed", Toast.LENGTH_SHORT).show(); - } - } else { - // Request has no resolution - Toast.makeText(activity, "Save failed", Toast.LENGTH_SHORT).show(); - } - } - } - } - );*/ - } - - public void deleteLoginState(String username, String password) { - if (!this.isAvailable()) { - Log.d(TAG, "STATUS: Google auth not available!"); - return; - } - Credential credential = new Credential.Builder(username) - .setPassword(password) - .build(); - Auth.CredentialsApi.delete(mCredentialsClient, credential).setResultCallback( - new ResultCallback() { - @Override - public void onResult(Status status) { - if (status.isSuccess()) { - // Credential was deleted successfully - } - } - } - ); - } - - - private boolean isAvailable() { - return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this.activity) == ConnectionResult.SUCCESS; - } - - private CredentialsClient getClient(@NonNull GoogleApiClient.ConnectionCallbacks connectionCallbacks, @NonNull GoogleApiClient.OnConnectionFailedListener failedListener) { - CredentialsOptions options = new CredentialsOptions.Builder() - .forceEnableSaveDialog() - .build(); - return com.google.android.gms.auth.api.credentials.Credentials.getClient(this.activity, options); - - - /*return new GoogleApiClient.Builder(this.activity) - .addConnectionCallbacks(connectionCallbacks) - .enableAutoManage(this.activity, failedListener) - .addApi(Auth.CREDENTIALS_API) - .build();*/ - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data); - - switch (requestCode) { - case RequestCode.RC_HINT: - // Drop into handling for RC_READ - case RequestCode.RC_READ: - if (resultCode == RESULT_OK) { - boolean isHint = (requestCode == RequestCode.RC_HINT); - Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY); - - processRetrievedCredential(credential, isHint); - } else { - Log.e(TAG, "Credential Read: NOT OK"); - showToast("Credential Read Failed"); - } - - mIsResolving = false; - break; - case RequestCode.RC_SAVE: - if (resultCode == RESULT_OK) { - Log.d(TAG, "Credential Save: OK"); - showToast("Credential Save Success"); - } else { - Log.e(TAG, "Credential Save: NOT OK"); - showToast("Credential Save Failed"); - } - - mIsResolving = false; - break; - } - } - - - private void resolveResult(ResolvableApiException rae, int requestCode) { - // We don't want to fire multiple resolutions at once since that can result - // in stacked dialogs after rotation or another similar event. - if (mIsResolving) { - Log.w(TAG, "resolveResult: already resolving."); - return; - } - - Log.d(TAG, "Resolving: " + rae); - try { - rae.startResolutionForResult(this.activity, requestCode); - mIsResolving = true; - } catch (IntentSender.SendIntentException e) { - Log.e(TAG, "STATUS: Failed to send resolution.", e); - } - } - - /** Display a short Toast message **/ - private void showToast(String msg) { - Toast.makeText(this.activity, msg, Toast.LENGTH_SHORT).show(); - } -}