Commit 0bdaf281 authored by Roger Barton's avatar Roger Barton
Browse files

Better fix for page view, added saving of userinfo between sessions

parent 337c18f6
...@@ -22,6 +22,7 @@ import ch.amiv.android_app.jobs.JobListAdapter; ...@@ -22,6 +22,7 @@ import ch.amiv.android_app.jobs.JobListAdapter;
/** /**
* This class is a fragment for a list screen used in the main activity by the page viewer for events, jobs, it will use the given page position to tell which one it is * This class is a fragment for a list screen used in the main activity by the page viewer for events, jobs, it will use the given page position to tell which one it is
* NOTE: This fragment will lose its connection to the parent activity, when the app is resumed, use MainActivity.instance as the activity and context
*/ */
public class ListFragment extends Fragment { public class ListFragment extends Fragment {
private int pagePosition; //the fragments page in the pageview of the main activity private int pagePosition; //the fragments page in the pageview of the main activity
...@@ -47,7 +48,7 @@ public class ListFragment extends Fragment { ...@@ -47,7 +48,7 @@ public class ListFragment extends Fragment {
public Requests.OnDataReceivedCallback onEventsListUpdatedCallback = new Requests.OnDataReceivedCallback() { public Requests.OnDataReceivedCallback onEventsListUpdatedCallback = new Requests.OnDataReceivedCallback() {
@Override @Override
public void OnDataReceived() { public void OnDataReceived() {
Requests.FetchEventSignups(recyclerView.getContext(), onSignupsUpdatedCallback, null, ""); Requests.FetchEventSignups(MainActivity.instance, onSignupsUpdatedCallback, null, "");
RefreshList(true); RefreshList(true);
} }
}; };
...@@ -97,29 +98,29 @@ public class ListFragment extends Fragment { ...@@ -97,29 +98,29 @@ public class ListFragment extends Fragment {
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override
public void onRefresh() { public void onRefresh() {
if(!(recyclerView.getContext() instanceof MainActivity)) if(!(MainActivity.instance instanceof MainActivity))
return; return;
if(pagePosition == PageType.EVENTS) if(pagePosition == PageType.EVENTS)
Requests.FetchEventList(recyclerView.getContext(), onEventsListUpdatedCallback, cancelRefreshCallback, ""); Requests.FetchEventList(MainActivity.instance, onEventsListUpdatedCallback, cancelRefreshCallback, "");
else if (pagePosition == PageType.JOBS) else if (pagePosition == PageType.JOBS)
Requests.FetchJobList(recyclerView.getContext(), onJobsListUpdatedCallback, cancelRefreshCallback, ""); Requests.FetchJobList(MainActivity.instance, onJobsListUpdatedCallback, cancelRefreshCallback, "");
} }
}); });
//refresh on activity start //refresh on activity start
swipeRefreshLayout.post(new Runnable() { swipeRefreshLayout.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if(!(recyclerView.getContext() instanceof MainActivity)) if(!(MainActivity.instance instanceof MainActivity))
return; return;
if(pagePosition == PageType.EVENTS) { if(pagePosition == PageType.EVENTS) {
SetRefreshUI(true); SetRefreshUI(true);
Requests.FetchEventList(recyclerView.getContext(), onEventsListUpdatedCallback, cancelRefreshCallback, ""); Requests.FetchEventList(MainActivity.instance, onEventsListUpdatedCallback, cancelRefreshCallback, "");
} }
else if(pagePosition == PageType.JOBS){ else if(pagePosition == PageType.JOBS){
SetRefreshUI(true); SetRefreshUI(true);
Requests.FetchJobList(recyclerView.getContext(), onJobsListUpdatedCallback, cancelRefreshCallback, ""); Requests.FetchJobList(MainActivity.instance, onJobsListUpdatedCallback, cancelRefreshCallback, "");
} }
} }
}); });
...@@ -130,17 +131,17 @@ public class ListFragment extends Fragment { ...@@ -130,17 +131,17 @@ public class ListFragment extends Fragment {
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
// use a linear layout manager // use a linear layout manager
recyclerLayoutAdapter = new LinearLayoutManager(recyclerView.getContext()); recyclerLayoutAdapter = new LinearLayoutManager(MainActivity.instance);
recyclerView.setLayoutManager(recyclerLayoutAdapter); recyclerView.setLayoutManager(recyclerLayoutAdapter);
// specify an adapter (see also next example) // specify an adapter (see also next example)
if(pagePosition == PageType.EVENTS) if(pagePosition == PageType.EVENTS)
recyclerAdapter = new EventsListAdapter(((Activity) recyclerView.getContext())); recyclerAdapter = new EventsListAdapter(((Activity) MainActivity.instance));
else if (pagePosition == PageType.JOBS) else if (pagePosition == PageType.JOBS)
recyclerAdapter = new JobListAdapter((Activity) recyclerView.getContext()); recyclerAdapter = new JobListAdapter((Activity) MainActivity.instance);
if(recyclerAdapter != null) { if(recyclerAdapter != null) {
recyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(recyclerView.getContext(), R.anim.layout_anim_falldown)); recyclerView.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(MainActivity.instance, R.anim.layout_anim_falldown));
recyclerView.setAdapter(recyclerAdapter); recyclerView.setAdapter(recyclerAdapter);
AnimateList(null); AnimateList(null);
...@@ -188,6 +189,9 @@ public class ListFragment extends Fragment { ...@@ -188,6 +189,9 @@ public class ListFragment extends Fragment {
if(recyclerAdapter != null) if(recyclerAdapter != null)
recyclerAdapter.RefreshData(); recyclerAdapter.RefreshData();
//Reconnect the fragment to the mainactivity
MainActivity.instance.pagerAdapter.ReconnectFragment(this, pagePosition);
} }
private void SetRefreshUI(boolean isRefreshing){ private void SetRefreshUI(boolean isRefreshing){
......
...@@ -79,10 +79,17 @@ public class LoginActivity extends AppCompatActivity { ...@@ -79,10 +79,17 @@ public class LoginActivity extends AppCompatActivity {
final String password = passwordField.getText().toString(); final String password = passwordField.getText().toString();
if(username.isEmpty()) { if(username.isEmpty()) {
Snackbar.make(submitButton, R.string.snack_fill_all_fields, Snackbar.LENGTH_SHORT).show(); Snackbar.make(submitButton, R.string.snack_fill_fields, Snackbar.LENGTH_SHORT).show();
return; return;
} }
if(password.isEmpty()){
UserInfo.SetEmailOnlyLogin(getApplicationContext(), username, false);
SetSubmitButtonState(false, true);
Settings.Vibrate(Settings.VibrateTime.NORMAL, getApplicationContext());
ReturnToCallingActivity(true);
}
//Does a POST request to sessions to create a session and get a token. Does *not* use the OAuth process, see api docs //Does a POST request to sessions to create a session and get a token. Does *not* use the OAuth process, see api docs
StringRequest request = new StringRequest(Request.Method.POST, Settings.API_URL + "sessions", null, null) StringRequest request = new StringRequest(Request.Method.POST, Settings.API_URL + "sessions", null, null)
{ {
...@@ -110,7 +117,7 @@ public class LoginActivity extends AppCompatActivity { ...@@ -110,7 +117,7 @@ public class LoginActivity extends AppCompatActivity {
submitButton.post(new Runnable() { submitButton.post(new Runnable() {
@Override @Override
public void run() { public void run() {
UserInfo.UpdateCurrent(json, true); UserInfo.UpdateCurrent(getApplicationContext(), json, true, false);
} }
}); });
} }
......
...@@ -34,6 +34,8 @@ import ch.amiv.android_app.util.PersistentStorage; ...@@ -34,6 +34,8 @@ import ch.amiv.android_app.util.PersistentStorage;
* This is the first screen. features: drawer, pageview with bottom navigation bar and within each page a list view. * This is the first screen. features: drawer, pageview with bottom navigation bar and within each page a list view.
*/ */
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
public static MainActivity instance;
//region - ====Variables==== //region - ====Variables====
private NavigationView drawerNavigation; private NavigationView drawerNavigation;
...@@ -43,7 +45,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -43,7 +45,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private BottomNavigationView bottomNavigation; private BottomNavigationView bottomNavigation;
private ViewPager viewPager; private ViewPager viewPager;
private PagerAdapter pagerAdapter; public PagerAdapter pagerAdapter;
/** /**
* Handle what should happen when the bottom nav buttons are pressed, will change the page of the viewpager * Handle what should happen when the bottom nav buttons are pressed, will change the page of the viewpager
...@@ -76,6 +78,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -76,6 +78,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
instance = this;
setContentView(R.layout.core_activity_main); setContentView(R.layout.core_activity_main);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
...@@ -98,8 +101,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -98,8 +101,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
new Settings(getApplicationContext()); //creates the settings instance, so we can store/retrieve shared preferences new Settings(getApplicationContext()); //creates the settings instance, so we can store/retrieve shared preferences
//fetch the user info if we are logged in, there exists a token from the previous session, should be cached. //fetch the user info if we are logged in, there exists a token from the previous session, should be cached.
if(Settings.IsLoggedIn(getApplicationContext()) && (UserInfo.current == null || UserInfo.current.nethz.isEmpty()))
{ if(!PersistentStorage.LoadUserInfo(getApplicationContext()) || UserInfo.current._id.isEmpty() && !Settings.IsEmailOnlyLogin(getApplicationContext())) {
Requests.FetchUserData(getApplicationContext(), drawerNavigation, new Requests.OnDataReceivedCallback() { Requests.FetchUserData(getApplicationContext(), drawerNavigation, new Requests.OnDataReceivedCallback() {
@Override @Override
public void OnDataReceived() { public void OnDataReceived() {
...@@ -153,16 +156,21 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -153,16 +156,21 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
*/ */
public void LogoutUser() public void LogoutUser()
{ {
if(Settings.IsEmailOnlyLogin(getApplicationContext())) {
Settings.SetToken("", getApplicationContext());
}
else {
//delete session at the server and then clear the token //delete session at the server and then clear the token
Requests.DeleteCurrentSession(getApplicationContext()); Requests.DeleteCurrentSession(getApplicationContext());
Events.ClearSignups();
}
PersistentStorage.ClearUser(getApplicationContext());
UserInfo.current = null; UserInfo.current = null;
Events.ClearSignups();
pagerAdapter.RefreshPage(ListFragment.PageType.EVENTS, true); pagerAdapter.RefreshPage(ListFragment.PageType.EVENTS, true);
SetLoginUIDirty(); SetLoginUIDirty();
System.gc();//run garbage collector explicitly to clean up user data
Requests.FetchEventList(getApplicationContext(), onEventsListUpdatedCallback, null, ""); Requests.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
} }
/** /**
...@@ -176,10 +184,16 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -176,10 +184,16 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
.setChecked(false); .setChecked(false);
if(UserInfo.current != null) if(UserInfo.current != null)
{ {
if(Settings.IsEmailOnlyLogin(getApplicationContext())) {
drawer_title.setText(UserInfo.current.email);
drawer_subtitle.setText(R.string.email_only_login);
}
else {
drawer_title.setText(UserInfo.current.firstname + " " + UserInfo.current.lastname); drawer_title.setText(UserInfo.current.firstname + " " + UserInfo.current.lastname);
drawer_subtitle.setText(UserInfo.current.email); drawer_subtitle.setText(UserInfo.current.email);
} }
} }
}
else else
{ {
drawerNavigation.getMenu().findItem(R.id.nav_login) drawerNavigation.getMenu().findItem(R.id.nav_login)
...@@ -245,28 +259,27 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -245,28 +259,27 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
*/ */
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0) { if (requestCode == 0 && resultCode == RESULT_OK) {
if (resultCode == RESULT_OK) {
// If we are returning from the login activity and have had a successfully login, refresh the user info and login UI // If we are returning from the login activity and have had a successfully login, refresh the user info and login UI
boolean refreshLogin = data.getBooleanExtra("login_success", false); boolean refreshLogin = data.getBooleanExtra("login_success", false);
if(refreshLogin && Settings.IsLoggedIn(getApplicationContext())) if(refreshLogin && Settings.IsLoggedIn(getApplicationContext()))
{ {
SetLoginUIDirty();
Requests.FetchUserData(getApplicationContext(), drawerNavigation, new Requests.OnDataReceivedCallback() { Requests.FetchUserData(getApplicationContext(), drawerNavigation, new Requests.OnDataReceivedCallback() {
@Override @Override
public void OnDataReceived() { public void OnDataReceived() {
SetLoginUIDirty(); SetLoginUIDirty();
//Update events and signups with the new userinfo //Update events and signups with the new userinfo
if(Events.eventInfos.size() > 0) if(Events.eventInfos.size() > 0)
Requests.FetchEventSignups(getApplicationContext(), onSignupsUpdatedCallback, null, ""); Requests.FetchEventSignups(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
else else
Requests.FetchEventList(getApplicationContext(), onEventsListUpdatedCallback, null, ""); Requests.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
} }
}); });
} }
} }
} }
}
//region =====TOOLBAR===== //region =====TOOLBAR=====
@Override @Override
...@@ -392,6 +405,20 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -392,6 +405,20 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
else else
Log.e("pageview", "RefreshPage(), Page does not exist will not refresh: " + position); Log.e("pageview", "RefreshPage(), Page does not exist will not refresh: " + position);
} }
/**
* Used to reconnect the link to the fragment in onresume
* @param fragment
* @param position
*/
public void ReconnectFragment(ListFragment fragment, int position){
try {
pages.set(position, fragment);
}
catch (Exception e){
e.printStackTrace();
}
}
} }
/** /**
......
package ch.amiv.android_app.core; package ch.amiv.android_app.core;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
...@@ -138,7 +137,7 @@ public final class Requests { ...@@ -138,7 +137,7 @@ public final class Requests {
@Override @Override
public Map<String, String> getHeaders() throws AuthFailureError { public Map<String, String> getHeaders() throws AuthFailureError {
if(Settings.IsLoggedIn(context)) { if(Settings.HasToken(context)) {
Map<String,String> headers = new HashMap<String, String>(); Map<String,String> headers = new HashMap<String, String>();
String credentials = Settings.GetToken(context) + ":"; String credentials = Settings.GetToken(context) + ":";
...@@ -163,7 +162,7 @@ public final class Requests { ...@@ -163,7 +162,7 @@ public final class Requests {
*/ */
public static void FetchEventSignups(final Context context, final OnDataReceivedCallback callback, final OnDataReceivedCallback errorCallback, @NonNull String eventId) public static void FetchEventSignups(final Context context, final OnDataReceivedCallback callback, final OnDataReceivedCallback errorCallback, @NonNull String eventId)
{ {
if(!Settings.IsLoggedIn(context) || UserInfo.current == null || UserInfo.current._id.isEmpty()) { if(!Settings.HasToken(context) || UserInfo.current == null || UserInfo.current._id.isEmpty()) {
RunCallback(errorCallback); RunCallback(errorCallback);
return; return;
} }
...@@ -303,7 +302,7 @@ public final class Requests { ...@@ -303,7 +302,7 @@ public final class Requests {
@Override @Override
public Map<String, String> getHeaders() throws AuthFailureError { public Map<String, String> getHeaders() throws AuthFailureError {
if(Settings.IsLoggedIn(context)) { if(Settings.HasToken(context)) {
Map<String,String> headers = new HashMap<String, String>(); Map<String,String> headers = new HashMap<String, String>();
String credentials = Settings.GetToken(context) + ":"; String credentials = Settings.GetToken(context) + ":";
...@@ -327,7 +326,7 @@ public final class Requests { ...@@ -327,7 +326,7 @@ public final class Requests {
*/ */
public static void FetchUserData(final Context context, final View view, final OnDataReceivedCallback callback) public static void FetchUserData(final Context context, final View view, final OnDataReceivedCallback callback)
{ {
if(!Settings.IsLoggedIn(context) || !CheckConnection(context)) if(!Settings.HasToken(context) || !CheckConnection(context))
return; return;
//Do request Token->User //Do request Token->User
...@@ -344,9 +343,7 @@ public final class Requests { ...@@ -344,9 +343,7 @@ public final class Requests {
callbackHandler.post(new Runnable() { callbackHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
UserInfo.UpdateCurrent(json, false); UserInfo.UpdateCurrent(context, json, false, false);
/*UserInfo user = new UserInfo(json, false);
user.SetAsCurrent();*/
} }
}); });
...@@ -398,11 +395,14 @@ public final class Requests { ...@@ -398,11 +395,14 @@ public final class Requests {
*/ */
public static void DeleteCurrentSession(final Context context) public static void DeleteCurrentSession(final Context context)
{ {
if(Settings.IsEmailOnlyLogin(context))
return;
final UserInfo user = UserInfo.current; final UserInfo user = UserInfo.current;
final String token = Settings.GetToken(context); final String token = Settings.GetToken(context);
Settings.SetToken("", context); Settings.SetToken("", context);
if(!Settings.IsLoggedIn(context) || UserInfo.current == null || UserInfo.current.session_id.isEmpty()) if(!Settings.HasToken(context) || UserInfo.current == null || UserInfo.current.session_id.isEmpty())
return; return;
//Do request Token->User //Do request Token->User
......
...@@ -5,8 +5,6 @@ import android.content.SharedPreferences; ...@@ -5,8 +5,6 @@ import android.content.SharedPreferences;
import android.os.Vibrator; import android.os.Vibrator;
import android.util.Log; import android.util.Log;
import java.security.PublicKey;
/** /**
* This class is used to save settings so they can be restored in another session later. * This class is used to save settings so they can be restored in another session later.
* Use this class to retrieve visible/hidden settings. * Use this class to retrieve visible/hidden settings.
...@@ -23,7 +21,7 @@ public class Settings { ...@@ -23,7 +21,7 @@ public class Settings {
//Vars for saving/reading the url from shared prefs, to allow saving between sessions. For each variable, have a key to access it and a default value //Vars for saving/reading the url from shared prefs, to allow saving between sessions. For each variable, have a key to access it and a default value
private static SharedPreferences sharedPrefs; private static SharedPreferences sharedPrefs;
private static final String SHARED_PREFS_KEY = "ch.amiv.android_app"; public static final String SHARED_PREFS_KEY = "ch.amiv.android_app";
private static final String apiUrlPrefKey = "ch.amiv.android_app.serverurl"; private static final String apiUrlPrefKey = "ch.amiv.android_app.serverurl";
private static final String defaultApiUrl = "https://api-dev.amiv.ethz.ch"; private static final String defaultApiUrl = "https://api-dev.amiv.ethz.ch";
private static final String themeKey = "ch.amiv.android_app.theme"; private static final String themeKey = "ch.amiv.android_app.theme";
...@@ -103,12 +101,27 @@ public class Settings { ...@@ -103,12 +101,27 @@ public class Settings {
* Note: will only check if a token exists. This token may have expired but not have been refreshed/deleted. * Note: will only check if a token exists. This token may have expired but not have been refreshed/deleted.
* @return True if the user is logged into the api and has an access token. * @return True if the user is logged into the api and has an access token.
*/ */
public static boolean IsLoggedIn(Context context){ public static boolean HasToken(Context context){
CheckInitSharedPrefs(context); CheckInitSharedPrefs(context);
String t = sharedPrefs.getString(apiTokenKey, ""); String t = sharedPrefs.getString(apiTokenKey, "");
return !t.isEmpty(); return !t.isEmpty();
} }
/**
* Will return whether the user is only loggedd in with an email, if they do not have an api login, false if current user has not be initialised
*/
public static boolean IsEmailOnlyLogin(Context context){
return !Settings.HasToken(context) && UserInfo.current != null && !UserInfo.current.email.isEmpty();
}
/**
* Note: will only check if a token exists. This token may have expired but not have been refreshed/deleted.
* @return True if the user is logged into the api and has an access token.
*/
public static boolean IsLoggedIn(Context context){
return HasToken(context) || IsEmailOnlyLogin(context);
}
// Theme // Theme
public static void SetIsDarkTheme(boolean value, Context context) { public static void SetIsDarkTheme(boolean value, Context context) {
......
package ch.amiv.android_app.core; package ch.amiv.android_app.core;
import android.content.Context;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
public class UserInfo { import java.io.Serializable;
import java.util.EmptyStackException;
import java.util.zip.CheckedOutputStream;
import ch.amiv.android_app.util.PersistentStorage;
public class UserInfo implements Serializable{
public static UserInfo current; public static UserInfo current;
public String _id = ""; public String _id = "";
...@@ -22,12 +30,23 @@ public class UserInfo { ...@@ -22,12 +30,23 @@ public class UserInfo {
public String department = ""; public String department = "";
public boolean send_newsletter = true; public boolean send_newsletter = true;
private UserInfo(JSONObject json, boolean isFromTokenRequest) private UserInfo(JSONObject json, boolean isFromTokenRequest)
{ {
Update(json, isFromTokenRequest); Update(json, isFromTokenRequest);
} }
private UserInfo (String email){
Update(email);
}
/**
* Used when the user only logs in with an email
* @param email_
*/
public void Update(String email_){
email = email_;
}
/**