Commit c887d453 authored by Roger Barton's avatar Roger Barton
Browse files

Refined settings and storage, changes to Events.java & AdditFields

Adding default additional fields
parent 3e7165e6
Pipeline #8539 passed with stages
in 2 minutes and 40 seconds
This is a sample of the "additional_fields" variable found in the json for an event
{ {
"$schema":"http://json-schema.org/draft-04/schema#", "$schema":"http://json-schema.org/draft-04/schema#",
"additionalProperties":false, "additionalProperties":false,
......
For POST request to signups, to send additional fields as part of the signup use this format
"additional_fields":
{
"SBB_Abo":"Halbtax",
"Food":"vegi"
}
\ No newline at end of file
...@@ -54,7 +54,7 @@ public class SettingsActivity extends AppCompatActivity { ...@@ -54,7 +54,7 @@ public class SettingsActivity extends AppCompatActivity {
Settings.SetBoolPref(Settings.checkin_autoUpdate, mAutoRefreshCheck.isChecked(), getApplicationContext()); Settings.SetBoolPref(Settings.checkin_autoUpdate, mAutoRefreshCheck.isChecked(), getApplicationContext());
Settings.SetFloatPref(Settings.checkin_refreshRate, MathUtils.clamp(Float.parseFloat(mRefreshFreqField.getText().toString()), 3f, Float.POSITIVE_INFINITY), getApplicationContext()); Settings.SetFloatPref(Settings.checkin_refreshRate, MathUtils.clamp(Float.parseFloat(mRefreshFreqField.getText().toString()), 3f, Float.POSITIVE_INFINITY), getApplicationContext());
ReturnToMainActivity(); finish();
} }
/** /**
...@@ -63,10 +63,4 @@ public class SettingsActivity extends AppCompatActivity { ...@@ -63,10 +63,4 @@ public class SettingsActivity extends AppCompatActivity {
public static int GetRefreshRateMillis(Context context) { public static int GetRefreshRateMillis(Context context) {
return (int)(1000 * Settings.GetFloatPref(Settings.checkin_refreshRate, context)); return (int)(1000 * Settings.GetFloatPref(Settings.checkin_refreshRate, context));
} }
private void ReturnToMainActivity ()
{
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
} }
...@@ -2,6 +2,7 @@ package ch.amiv.android_app.core; ...@@ -2,6 +2,7 @@ package ch.amiv.android_app.core;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
...@@ -17,6 +18,7 @@ import android.widget.LinearLayout; ...@@ -17,6 +18,7 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import ch.amiv.android_app.R; import ch.amiv.android_app.R;
import ch.amiv.android_app.events.AdditField;
import ch.amiv.android_app.util.ui.NonSwipeableViewPager; import ch.amiv.android_app.util.ui.NonSwipeableViewPager;
import ch.amiv.android_app.util.ui.EnumViewGenerator; import ch.amiv.android_app.util.ui.EnumViewGenerator;
import ch.amiv.android_app.util.Util; import ch.amiv.android_app.util.Util;
...@@ -286,6 +288,10 @@ public class IntroActivity extends AppCompatActivity { ...@@ -286,6 +288,10 @@ public class IntroActivity extends AppCompatActivity {
private void StartMainAcivity() { private void StartMainAcivity() {
Settings.SetBoolPref(Settings.introDoneKey, true, this); Settings.SetBoolPref(Settings.introDoneKey, true, this);
// TODO check if notifications are enabled in the settings
Notifications.set_Alarm(this);
startActivity(new Intent(this, MainActivity.class)); startActivity(new Intent(this, MainActivity.class));
finish(); finish();
} }
...@@ -367,7 +373,7 @@ public class IntroActivity extends AppCompatActivity { ...@@ -367,7 +373,7 @@ public class IntroActivity extends AppCompatActivity {
} }
}; };
EnumViewGenerator.InitialiseEnumList(this, R.string.pref_food_title, onClick, getResources().getStringArray(R.array.pref_food_list_values), true); EnumViewGenerator.InitialiseEnumList(this, onClick, AdditField.Defaults.food, true);
btnNext.setOnClickListener(new View.OnClickListener() { btnNext.setOnClickListener(new View.OnClickListener() {
@Override @Override
...@@ -398,7 +404,7 @@ public class IntroActivity extends AppCompatActivity { ...@@ -398,7 +404,7 @@ public class IntroActivity extends AppCompatActivity {
} }
}; };
EnumViewGenerator.InitialiseEnumList(this, R.string.pref_sbb_title, onClick, getResources().getStringArray(R.array.pref_sbb_list_values), false); EnumViewGenerator.InitialiseEnumList(this, onClick, AdditField.Defaults.sbbAbo, false);
btnNext.setOnClickListener(new View.OnClickListener() { btnNext.setOnClickListener(new View.OnClickListener() {
@Override @Override
......
...@@ -31,7 +31,6 @@ import ch.amiv.android_app.R; ...@@ -31,7 +31,6 @@ import ch.amiv.android_app.R;
import ch.amiv.android_app.events.EventDetailActivity; import ch.amiv.android_app.events.EventDetailActivity;
import ch.amiv.android_app.events.Events; import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.jobs.JobDetailActivity; import ch.amiv.android_app.jobs.JobDetailActivity;
import ch.amiv.android_app.util.PersistentStorage;
import ch.amiv.android_app.util.Util; import ch.amiv.android_app.util.Util;
...@@ -123,16 +122,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On ...@@ -123,16 +122,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
bottomNavigation = findViewById(R.id.bottomNav); bottomNavigation = findViewById(R.id.bottomNav);
bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
PersistentStorage.LoadEvents(getApplicationContext()); Settings.LoadEvents(getApplicationContext());
PersistentStorage.LoadJobs(getApplicationContext()); Settings.LoadJobs(getApplicationContext());
InitialisePageView(); InitialisePageView();
// TODO check if notifications are enabled in the settings
Notifications.set_Alarm(this);
//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(!PersistentStorage.LoadUserInfo(getApplicationContext()) || UserInfo.current._id.isEmpty() && !Settings.IsEmailOnlyLogin(getApplicationContext())) { if(!Settings.LoadUserInfo(getApplicationContext()) || UserInfo.current._id.isEmpty() && !Settings.IsEmailOnlyLogin(getApplicationContext())) {
Request.FetchUserData(getApplicationContext(), drawerNav, new Request.OnDataReceivedCallback() { Request.FetchUserData(getApplicationContext(), drawerNav, new Request.OnDataReceivedCallback() {
@Override @Override
public void OnDataReceived() { public void OnDataReceived() {
......
...@@ -120,7 +120,7 @@ public final class Notifications { ...@@ -120,7 +120,7 @@ public final class Notifications {
// get event from JSONObject and add it to events list // get event from JSONObject and add it to events list
JSONObject event = items.getJSONObject(0); JSONObject event = items.getJSONObject(0);
Events.AddEvent(event); Events.AddEvent(event, context);
// refetch event list to add new event // refetch event list to add new event
String event_id = (String) event.get("_id"); String event_id = (String) event.get("_id");
...@@ -148,7 +148,7 @@ public final class Notifications { ...@@ -148,7 +148,7 @@ public final class Notifications {
String [] event_id = new String[items.length()]; String [] event_id = new String[items.length()];
for(int i = 0; i<items.length();i++){ for(int i = 0; i<items.length();i++){
JSONObject event = items.getJSONObject(i); JSONObject event = items.getJSONObject(i);
Events.AddEvent(event); // TODO efficiency ! Events.AddEvent(event, context); // TODO efficiency !
event_id[i]= (String) event.get("_id"); event_id[i]= (String) event.get("_id");
} }
......
...@@ -7,9 +7,20 @@ import android.content.res.Resources; ...@@ -7,9 +7,20 @@ import android.content.res.Resources;
import android.os.Vibrator; import android.os.Vibrator;
import android.util.Pair; import android.util.Pair;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.json.JSONObject;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import ch.amiv.android_app.R; import ch.amiv.android_app.R;
import ch.amiv.android_app.events.EventInfo;
import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.jobs.JobInfo;
import ch.amiv.android_app.jobs.Jobs;
/** /**
* 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.
...@@ -35,6 +46,11 @@ public class Settings { ...@@ -35,6 +46,11 @@ public class Settings {
public static final String[] specialFoodPrefKey = {"core.special_food_pref", ""}; public static final String[] specialFoodPrefKey = {"core.special_food_pref", ""};
public static final String[] sbbPrefKey = {"core.sbb_abo", ""}; public static final String[] sbbPrefKey = {"core.sbb_abo", ""};
//Storing of larger data
public static final String[] userInfoKey = {"core.user_info", ""};
public static final String[] eventInfoKey = {"events.event_infos", ""};
public static final String[] jobInfoKey = {"jobs.job_infos", ""};
//region---Check-in---- //region---Check-in----
public static final String[] recentEventPin = {"checkin.recent_event_pin", ""}; public static final String[] recentEventPin = {"checkin.recent_event_pin", ""};
public static final String[] checkin_url = {"checkin.serverurl", "https://checkin.amiv.ethz.ch"}; public static final String[] checkin_url = {"checkin.serverurl", "https://checkin.amiv.ethz.ch"};
...@@ -55,6 +71,11 @@ public class Settings { ...@@ -55,6 +71,11 @@ public class Settings {
sharedPrefs = context.getSharedPreferences(SHARED_PREFS_KEY, Context.MODE_PRIVATE); sharedPrefs = context.getSharedPreferences(SHARED_PREFS_KEY, Context.MODE_PRIVATE);
} }
public static boolean HasKey(String[] key, Context context){
CheckInitSharedPrefs(context);
return sharedPrefs.contains(key[0]);
}
/** /**
* Will store the value in sharedpreferences to be restored in another session * Will store the value in sharedpreferences to be restored in another session
* @param key A string[2] in the format (prefs key, defValue), use the Settings public vars * @param key A string[2] in the format (prefs key, defValue), use the Settings public vars
...@@ -87,6 +108,11 @@ public class Settings { ...@@ -87,6 +108,11 @@ public class Settings {
} }
// Sidenote: Float prefs need to use a pair instead of a string[], so we have a float for the default value // Sidenote: Float prefs need to use a pair instead of a string[], so we have a float for the default value
public static boolean HasKey(Pair<String, Float> key, Context context){
CheckInitSharedPrefs(context);
return sharedPrefs.contains(key.first);
}
public static void SetFloatPref (Pair<String, Float> key, float value, Context context){ public static void SetFloatPref (Pair<String, Float> key, float value, Context context){
CheckInitSharedPrefs(context); CheckInitSharedPrefs(context);
sharedPrefs.edit().putFloat(key.first, value).apply(); sharedPrefs.edit().putFloat(key.first, value).apply();
...@@ -139,7 +165,7 @@ public class Settings { ...@@ -139,7 +165,7 @@ public class Settings {
* Will return whether the user is only logged in with an email, if they do not have an api login, false if current user has not be initialised * Will return whether the user is only logged 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){ public static boolean IsEmailOnlyLogin(Context context){
return !Settings.HasToken(context) && UserInfo.current != null && !UserInfo.current.email.isEmpty(); return !HasToken(context) && UserInfo.current != null && !UserInfo.current.email.isEmpty();
} }
/** /**
...@@ -195,4 +221,118 @@ public class Settings { ...@@ -195,4 +221,118 @@ public class Settings {
vibrator.cancel(); vibrator.cancel();
} }
//endregion //endregion
//============Storing User,Event,Job Infos===============
//region user,events,jobs
private static final Type eventListType = new TypeToken<List<EventInfo>>() {}.getType();
private static final Type jobListType = new TypeToken<List<JobInfo>>() {}.getType();
private static boolean hasLoadedUser = false;
private static boolean hasLoadedEvents = false;
private static boolean hasLoadedJobs = false;
public static void SaveUserInfo(Context context)
{
Gson gson = new Gson();
String json = gson.toJson(UserInfo.current);
SetPref(userInfoKey, json, context);
}
public static boolean LoadUserInfo (Context context)
{
if(hasLoadedUser || !HasKey(userInfoKey, context)) return false;
String json = GetPref(userInfoKey, context);
if(json.isEmpty())
return false;
try {
UserInfo.UpdateCurrent(context, new JSONObject(json), false, true);
}
catch (Exception e){ //This may happen if the userinfo class changes
e.printStackTrace();
return false;
}
hasLoadedUser = true;
return true;
}
/**
* Clears the stored userinfo, done in async
*/
public static void ClearUser(Context context) {
SetPref(userInfoKey, "", context);
}
//region - Events
public static void SaveEvents(Context context)
{
Gson gson = new Gson();
String json = gson.toJson(Events.eventInfos, eventListType);
SetPref(eventInfoKey, json, context);
}
public static boolean LoadEvents (Context context)
{
if(hasLoadedEvents || !HasKey(eventInfoKey, context)) return false;
String json = GetPref(eventInfoKey, context);
if(json.isEmpty())
return false;
try {
Gson gson = new Gson();
Events.eventInfos = gson.fromJson(json, eventListType);
Events.GenerateSortedLists(true);
}
catch (Exception e){ //This may happen if the userinfo class changes
e.printStackTrace();
return false;
}
hasLoadedEvents = true;
return true;
}
public static void ClearEvents(Context context) {
SetPref(eventInfoKey, "", context);
}
//endregion
//region - Jobs
public static void SaveJobs(Context context)
{
Gson gson = new Gson();
String json = gson.toJson(Jobs.jobInfos, jobListType);
SetPref(jobInfoKey, json, context);
}
public static boolean LoadJobs (Context context)
{
if(hasLoadedJobs || !HasKey(jobInfoKey, context)) return false;
String json = GetPref(jobInfoKey, context);
if(json.isEmpty())
return false;
try {
Gson gson = new Gson();
Jobs.jobInfos = gson.fromJson(json, jobListType);
Jobs.GenerateSortedLists(true);
}
catch (Exception e){ //This may happen if the userinfo class changes
e.printStackTrace();
return false;
}
hasLoadedJobs = true;
return true;
}
public static void ClearJobs(Context context) {
SetPref(jobInfoKey, "", context);
}
//endregion
///endregion
} }
...@@ -2,8 +2,6 @@ package ch.amiv.android_app.core; ...@@ -2,8 +2,6 @@ package ch.amiv.android_app.core;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.media.Ringtone; import android.media.Ringtone;
import android.media.RingtoneManager; import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
...@@ -20,8 +18,6 @@ import android.support.v7.app.ActionBar; ...@@ -20,8 +18,6 @@ import android.support.v7.app.ActionBar;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.MenuItem; import android.view.MenuItem;
import java.util.Locale;
import ch.amiv.android_app.R; import ch.amiv.android_app.R;
/** /**
......
...@@ -8,7 +8,6 @@ import org.json.JSONObject; ...@@ -8,7 +8,6 @@ import org.json.JSONObject;
import java.io.Serializable; import java.io.Serializable;
import ch.amiv.android_app.events.Events; import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.util.PersistentStorage;
public class UserInfo implements Serializable{ public class UserInfo implements Serializable{
public static UserInfo current; public static UserInfo current;
...@@ -110,7 +109,7 @@ public class UserInfo implements Serializable{ ...@@ -110,7 +109,7 @@ public class UserInfo implements Serializable{
} }
if(!isSavedInstance) if(!isSavedInstance)
PersistentStorage.SaveUserInfo(context); Settings.SaveUserInfo(context);
} }
public static void SetEmailOnlyLogin(Context context, String email, boolean isSavedInstance){ public static void SetEmailOnlyLogin(Context context, String email, boolean isSavedInstance){
...@@ -121,7 +120,7 @@ public class UserInfo implements Serializable{ ...@@ -121,7 +120,7 @@ public class UserInfo implements Serializable{
} }
if(!isSavedInstance) if(!isSavedInstance)
PersistentStorage.SaveUserInfo(context); Settings.SaveUserInfo(context);
} }
/** /**
...@@ -146,7 +145,7 @@ public class UserInfo implements Serializable{ ...@@ -146,7 +145,7 @@ public class UserInfo implements Serializable{
Events.ClearSignups(); Events.ClearSignups();
} }
PersistentStorage.ClearUser(context); Settings.ClearUser(context);
UserInfo.current = null; UserInfo.current = null;
} }
......
package ch.amiv.android_app.events; package ch.amiv.android_app.events;
import android.graphics.drawable.AdaptiveIconDrawable; import android.content.Context;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
...@@ -11,6 +11,8 @@ import java.util.Arrays; ...@@ -11,6 +11,8 @@ import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import ch.amiv.android_app.R;
/** /**
* A data class for storing a single additional Field for an event. See the SampleEventAdditFields file. * A data class for storing a single additional Field for an event. See the SampleEventAdditFields file.
* An instance of this class represents one variable. * An instance of this class represents one variable.
...@@ -28,13 +30,42 @@ public class AdditField { ...@@ -28,13 +30,42 @@ public class AdditField {
public static final int STRING = 6; public static final int STRING = 6;
} }
public int type; //Use the FieldType constants, the currentValue should then be of that type public int type = FieldType.STRING; //Use the FieldType constants, the currentValue should then be of that type
public String name; private String name = "";
public boolean required; private int resName = 0;
public String title(Context context){ //For multi-lingual support on default additFields, use this function instead
if(resName > 0)
return context.getResources().getString(resName);
else
return name;
}
public boolean required = false;
public String[] possibleValues; public String[] possibleValues = new String[0];
public String currentValue; public String currentValue = "";
public AdditField (){ }
public AdditField (int type_, String name_, boolean required_, String[] possibleValues_){
type = type_;
name = name_;
required = required_;
possibleValues = possibleValues_;
}
public AdditField (int type_, int resName_, boolean required_, String[] possibleValues_){
type = type_;
resName = resName_;
required = required_;
possibleValues = possibleValues_;
}
public static class Defaults {
public static AdditField sbbAbo = new AdditField(FieldType.STRING, R.string.pref_sbb_title, false, new String[]{"GA", "Gleis 7", "Halbtax", "None"});
public static AdditField food = new AdditField(FieldType.STRING, R.string.pref_food_title, false, new String[]{"Omnivore","Vegi","Vegan","Other"});
public static AdditField specialFoodReq = new AdditField(FieldType.STRING, R.string.pref_special_food_title, false, new String[0]);
}
/** /**
* *
* @param additional_fields The 'additional_fields' JsonObject from the event json * @param additional_fields The 'additional_fields' JsonObject from the event json
......
package ch.amiv.android_app.events; package ch.amiv.android_app.events;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.os.Bundle; import android.os.Bundle;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.content.res.ResourcesCompat; import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.InputType;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
...@@ -16,6 +19,7 @@ import android.view.animation.Animation; ...@@ -16,6 +19,7 @@ import android.view.animation.Animation;
import android.view.animation.LinearInterpolator; import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;