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

Moved Events/Jobs to generic base class (Items in issue #7)

Combined Events and Jobs into the ApiListBase file, all functionality is now shared for managing the lists of events and jobs.
Events, Jobs inherit from ApiListBase
EventInfo, JobInfo inherti from ApiItemBase, for easy use within the ApiListBase
individual events/jobs can now be easily accessed by indexes, ids, or intent using the LauncherExtras in ApiListBase
JobDetailActivity can now be launched with such an intent as well.
parent 8e038daf
Pipeline #8800 passed with stages
in 3 minutes and 57 seconds
......@@ -31,6 +31,7 @@ import ch.amiv.android_app.R;
import ch.amiv.android_app.events.EventDetailActivity;
import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.jobs.JobDetailActivity;
import ch.amiv.android_app.util.ApiListBase.LauncherExtras;
import ch.amiv.android_app.util.Util;
......@@ -246,16 +247,16 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public void StartEventDetailActivity(int eventGroup, int eventIndex)
{
Intent intent = new Intent(this, EventDetailActivity.class);
intent.putExtra(EventDetailActivity.LauncherExtras.EVENT_GROUP, eventGroup);
intent.putExtra(EventDetailActivity.LauncherExtras.EVENT_INDEX, eventIndex);
intent.putExtra(LauncherExtras.ITEM_GROUP, eventGroup);
intent.putExtra(LauncherExtras.ITEM_INDEX, eventIndex);
startActivityForResult(intent, 0);
}
public void StartJobDetailActivity(int jobGroup, int jobIndex)
{
Intent intent = new Intent(this, JobDetailActivity.class);
intent.putExtra(JobDetailActivity.LauncherExtras.JOB_GROUP, jobGroup);
intent.putExtra(JobDetailActivity.LauncherExtras.JOB_INDEX, jobIndex);
intent.putExtra(LauncherExtras.ITEM_GROUP, jobGroup);
intent.putExtra(LauncherExtras.ITEM_INDEX, jobIndex);
startActivityForResult(intent, 0);
}
......@@ -275,7 +276,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public void OnDataReceived() {
SetLoginUIDirty();
//Update events and signups with the new userinfo
if(Events.eventInfos.size() > 0)
if(Events.get.data.size() > 0)
Request.FetchEventSignups(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
else
Request.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
......
......@@ -16,6 +16,7 @@ import java.util.Calendar;
import ch.amiv.android_app.R;
import ch.amiv.android_app.events.EventDetailActivity;
import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.util.ApiListBase;
public final class Notifications {
public static AlarmManager alarm;
......@@ -120,7 +121,7 @@ public final class Notifications {
// get event from JSONObject and add it to events list
JSONObject event = items.getJSONObject(0);
Events.AddEvent(event, context);
Events.get.AddItem(event, context);
// refetch event list to add new event
String event_id = (String) event.get("_id");
......@@ -131,8 +132,8 @@ public final class Notifications {
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, EventDetailActivity.class);
notificationIntent.putExtra(EventDetailActivity.LauncherExtras.EVENT_ID, event_id);
notificationIntent.putExtra(EventDetailActivity.LauncherExtras.LOAD_EVENTS, true);
notificationIntent.putExtra(ApiListBase.LauncherExtras.ITEM_ID, event_id);
notificationIntent.putExtra(ApiListBase.LauncherExtras.RELOAD_FIRST, true);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
......@@ -148,7 +149,7 @@ public final class Notifications {
String [] event_id = new String[items.length()];
for(int i = 0; i<items.length();i++){
JSONObject event = items.getJSONObject(i);
Events.AddEvent(event, context); // TODO efficiency !
Events.get.AddItem(event, context); // TODO efficiency !
event_id[i]= (String) event.get("_id");
}
......@@ -176,7 +177,6 @@ public final class Notifications {
Notifications.notify_pending(context, "Many new Events added", titles_list.toString(), R.drawable.ic_amiv_logo_icon, pendingIntent);
}
}
// sets last change check to current time
......@@ -186,15 +186,5 @@ public final class Notifications {
}catch(JSONException ex){
// TODO
}
}
}
......@@ -201,9 +201,9 @@ public final class Request {
public void run() {
try {
if(eventId.isEmpty())
Events.UpdateEventInfos(context, json.getJSONArray("_items"));
Events.get.UpdateAll(context, json.getJSONArray("_items"));
else
Events.UpdateSingleEvent(json, eventId);
Events.get.UpdateItem(json, eventId, context);
if(callback != null)
callback.OnDataReceived();
} catch (JSONException e) {
......@@ -260,7 +260,7 @@ public final class Request {
}
/**
* Will fetch the event signups for the current user and save them in the eventInfos list
* Will fetch the event signups for the current user and save them in the data list
* @param eventId to only fetch for a specific event id add this, else set as empty
*/
public static void FetchEventSignups(final Context context, final OnDataReceivedCallback callback, final OnDataReceivedCallback errorCallback, @NonNull String eventId)
......@@ -289,7 +289,7 @@ public final class Request {
Runnable runnable = new Runnable() {
@Override
public void run() {
Events.AddSignupArray(signupsJson);
Events.get.AddSignupArray(signupsJson);
if(callback != null)
callback.OnDataReceived();
}
......@@ -366,9 +366,9 @@ public final class Request {
public void run() {
try {
if(jobId.isEmpty())
Jobs.UpdateJobInfos(context, json.getJSONArray("_items"));
Jobs.get.UpdateAll(context, json.getJSONArray("_items"));
else
Jobs.UpdateSingleJob(json, jobId);
Jobs.get.UpdateItem(json, jobId, context);
if(callback != null)
callback.OnDataReceived();
} catch (JSONException e) {
......
......@@ -269,7 +269,7 @@ public class Settings {
public static void SaveEvents(Context context)
{
Gson gson = new Gson();
String json = gson.toJson(Events.eventInfos, eventListType);
String json = gson.toJson(Events.get.data, eventListType);
SetPref(eventInfoKey, json, context);
}
......@@ -283,8 +283,8 @@ public class Settings {
try {
Gson gson = new Gson();
Events.eventInfos = gson.fromJson(json, eventListType);
Events.GenerateSortedLists(true);
Events.get.data = gson.fromJson(json, eventListType);
Events.get.GenerateSortedLists(true);
}
catch (Exception e){ //This may happen if the userinfo class changes
e.printStackTrace();
......@@ -304,7 +304,7 @@ public class Settings {
public static void SaveJobs(Context context)
{
Gson gson = new Gson();
String json = gson.toJson(Jobs.jobInfos, jobListType);
String json = gson.toJson(Jobs.get.data, jobListType);
SetPref(jobInfoKey, json, context);
}
......@@ -318,8 +318,8 @@ public class Settings {
try {
Gson gson = new Gson();
Jobs.jobInfos = gson.fromJson(json, jobListType);
Jobs.GenerateSortedLists(true);
Jobs.get.data = gson.fromJson(json, jobListType);
Jobs.get.GenerateSortedLists(true);
}
catch (Exception e){ //This may happen if the userinfo class changes
e.printStackTrace();
......
......@@ -142,7 +142,7 @@ public class UserInfo implements Serializable{
else {
//delete session at the server and then clear the token
Request.DeleteCurrentSession(context);
Events.ClearSignups();
Events.get.ClearSignups();
}
Settings.ClearUser(context);
......
......@@ -22,8 +22,8 @@ public class MainActivity extends AppCompatActivity {
String firstname = UserInfo.current.firstname;
//To access events use
EventInfo eventInfo = Events.sortedEventInfos.get(0).get(1);//sorted into groups by date
eventInfo = Events.eventInfos.get(0);//unsorted list
EventInfo eventInfo = Events.sorted.get(0).get(1);//sorted into groups by date
eventInfo = Events.data.get(0);//unsorted list
//To Send a request to the api or elsewhere see core.Request class for examples. Basic structure is as below
//START of request
......
......@@ -54,23 +54,14 @@ import ch.amiv.android_app.util.Util;
* This mainly displays stored info about the event, eg description and also fetches more such as images. Also handles registering for and event and the possible outcomes
*
* To launch this activity, you need to provide an event to view. You need to provide this as an intent extra (use intent.putExtra()):
* - Provide eventGroup == -1, eventGroup == index in Events.eventInfos (unsorted list)
* - Provide eventGroup == group in Events.sortedEventInfos, eventGroup == index in Events.sortedEventInfos (sorted list)
* - Provide eventGroup == -1, eventGroup == index in Events.data (unsorted list)
* - Provide eventGroup == group in Events.sorted, eventGroup == index in Events.sorted (sorted list)
* - Provide eventId == any valid event id
*
* If the event is not found, the activity finishes and returns to the calling activity.
*/
public class EventDetailActivity extends AppCompatActivity {
/**
* A constant class to easily set extras for launching the EventDetailActivity
*/
public static final class LauncherExtras {
public static final String EVENT_GROUP = "eventGroup";
public static final String EVENT_INDEX = "eventIndex";
public static final String EVENT_ID = "eventId";
public static final String LOAD_EVENTS = "loadEvents";
}
//region - Variables
private EventInfo event;
private ImageView posterImage;
......@@ -107,6 +98,19 @@ public class EventDetailActivity extends AppCompatActivity {
swipeRefreshLayout.setRefreshing(false);
}
};
//endregion
/**
* This will retrieve the eventIndexes to display, is only set when we originate from the MainActivity, where the int is added to the intent.
*/
private void GetIntentData (){
Intent intent = getIntent();
event = Events.get.GetItem(intent, getApplicationContext());
if(event == null)
ReturnToCallingActivity(false);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
......@@ -159,39 +163,6 @@ public class EventDetailActivity extends AppCompatActivity {
finish();
}
/**
* This will retrieve the eventIndexes to display, is only set when we originate from the MainActivity, where the int is added to the intent.
*/
private void GetIntentData (){
Intent intent = getIntent();
if(intent.getBooleanExtra(LauncherExtras.LOAD_EVENTS, false))
Settings.LoadEvents(getApplicationContext());
if(intent.hasExtra(LauncherExtras.EVENT_GROUP) && intent.hasExtra(LauncherExtras.EVENT_INDEX))
{
int eventGroup = intent.getIntExtra(LauncherExtras.EVENT_GROUP, 0);
int eventIndex = intent.getIntExtra(LauncherExtras.EVENT_INDEX, 0);
if(eventGroup == -1)
event = Events.eventInfos.get(eventIndex);
else
event = Events.sortedEventInfos.get(eventGroup).get(eventIndex);
if (event == null)
Log.e("events", "invalid event index selected during InitUI(), (groupIndex, eventIndex): (" + eventGroup + "," + eventIndex + "), total event size" + Events.eventInfos.size() + ". Ensure that you are not clearing/overwriting the events list while viewing an event. Returning to calling activity...");
}
else if(intent.hasExtra(LauncherExtras.EVENT_ID))
{
event = Events.GetEventById(intent.getStringExtra(LauncherExtras.EVENT_ID));
if(event == null)
Log.e("events", "No event found from eventId=" + intent.getStringExtra(LauncherExtras.EVENT_ID) + " in intent, have you used intent.putStringExtra. Returning to calling activity...");
}
if(event == null)
ReturnToCallingActivity(false);
}
/**
* This initialises UI variables and sets up various UI elements
*/
......
......@@ -15,6 +15,7 @@ import java.util.Locale;
import ch.amiv.android_app.R;
import ch.amiv.android_app.core.Request;
import ch.amiv.android_app.util.ApiItemBase;
import ch.amiv.android_app.util.Util;
import static ch.amiv.android_app.util.Util.BuildFileUrl;
......@@ -22,9 +23,9 @@ import static ch.amiv.android_app.util.Util.BuildFileUrl;
/**
* This is all the data about one event AND the current users signup data about that event
*/
public class EventInfo implements Serializable{
public class EventInfo extends ApiItemBase implements Serializable{
//region - ====Variables====
public String _id;
//public String _id; //inherited from ApiItemBase
public String _etag;
private String title_de;
private String title_en;
......@@ -74,13 +75,13 @@ public class EventInfo implements Serializable{
//endregion
public EventInfo(JSONObject json) {
UpdateEvent(json);
Update(json);
}
/**
* Overwrite the current data
*/
public void UpdateEvent(JSONObject json)
public void Update(JSONObject json)
{
_id = json.optString("_id");
_etag = json.optString("_etag");
......
package ch.amiv.android_app.events;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import ch.amiv.android_app.core.Settings;
import ch.amiv.android_app.util.ApiListBase;
/**
* This is the central place for storing information about the events, events + signups.
* Attention! eventInfo and sortedEventInfos indexes may change, the events will allways be sorted according to the adDateComparator.
* Attention! eventInfo and sorted indexes may change, the events will allways be sorted according to the adDateComparator.
*/
public final class Events {
public static List<EventInfo> eventInfos = new ArrayList<EventInfo>(); //This is a list of ALL events as received from the api, we will not use this directly
public static List<List<EventInfo>> sortedEventInfos = new ArrayList<>(EventGroup.SIZE); //A list of lists which has been sorted according to the EventGroup configuration
public class Events extends ApiListBase<EventInfo> {
//region - Variables
public static Events get = new Events();
public static boolean[] invertEventGroupSorting = new boolean[] {false, false, false, true}; //used to invert date sorting for the event groups
public static final int DAYS_NEW_TAG_ACTIVE = 3; //Defines for how many days after the ad start date the new tag is visible for
/**
* Use this class to use the correct indexes for the event group for the sorted list.
* Sidenote: we use the term 'group' and 'category' interchangeably
*/
//Use this class to use the correct indexes for the event group for the sortedEventInfos list
public static final class EventGroup {
public static final int SIZE = 4;
public static final int HIDDEN_EVENTS = 0;
public static final int CURRENT_EVENTS = 1;
public static final int CLOSED_EVENTS = 2;
public static final int PAST_EVENTS = 3;
}
//Defines for how many days after the ad start date the new tag is visible for
public static final int DAYS_NEW_TAG_ACTIVE = 3;
private static final int HIDDEN_EVENTS_EXP_SIZE = 2;
private static final int CURRENT_EVENTS_EXP_SIZE = 10;
private static final int CLOSED_EVENTS_EXP_SIZE = 5;
private static final int PAST_EVENTS_EXP_SIZE = 20;
}
private static Comparator<EventInfo> adDateComparator = new Comparator<EventInfo>() {
@Override
......@@ -45,159 +51,82 @@ public final class Events {
}
};
/**
* This is the key function of this class. It converts a json for several events to java EventInfos
* Update the event infos with the data received from the api. This is just for updating information about the event NOT the signup
* @param json json array of the events.
*/
public static void UpdateEventInfos(Context context, JSONArray json)
{
boolean isInitialising = eventInfos.size() == 0;
for (int i = 0; i < json.length(); i++)
{
try {
//if we are not initialising, search for the event id and then update it, else add a new one to the list. This ensures we do not lose the signup data
JSONObject jsonEvent = json.getJSONObject(i);
EventInfo e = new EventInfo(jsonEvent);
if(e._id.isEmpty())
continue;
if(isInitialising || !UpdateSingleEvent(jsonEvent, e._id))
eventInfos.add(e);
} catch (JSONException e) {
e.printStackTrace();
}
}
GenerateSortedLists(isInitialising);
Settings.SaveEvents(context);
}
public static void GenerateSortedLists(boolean isInitialising)
{
if(isInitialising){
sortedEventInfos = new ArrayList<>(EventGroup.SIZE);
for (int k = 0; k < EventGroup.SIZE; k++)
sortedEventInfos.add(new ArrayList<EventInfo>());
}
else {
for (int k = 0; k < sortedEventInfos.size(); k++)
sortedEventInfos.get(k).clear();
@Override
public Comparator<EventInfo> GetItemComparator() {
return adDateComparator;
}
//endregion
//Sort list and update sorted list
if(!eventInfos.isEmpty()){
//sort so first elem has an advertising start date furthest in the future
Collections.sort(eventInfos, adDateComparator);
//fill in the sorted list according to the dates of the events
for (int i = 0; i < eventInfos.size(); i++){
AddEventToSorted(eventInfos.get(i), false);
}
}
//region - Override functions from ApiListBase
/**
* @return An instance of EventInfo parsed from the json
*/
@Override
public EventInfo CreateItem(JSONObject json) {
return new EventInfo(json);
}
/**
* Will add the event to the sorted array. Use AddEvent to add an event, this is just used to update the sortedEventInfos list accordingly
* @param sortAfterInsert Will resort the group after insertion, by date
* @return The amount of categories in the sorted array, 1st dim
*/
private static void AddEventToSorted(EventInfo eventInfo, boolean sortAfterInsert){
Date today = Calendar.getInstance().getTime();
int group;
if(eventInfo.time_advertising_start.after(today)) //Determine which group the event is in, by date
group = EventGroup.HIDDEN_EVENTS;
else if(eventInfo.time_register_end.after(today))
group = EventGroup.CURRENT_EVENTS;
else if(eventInfo.time_end.after(today))
group = EventGroup.CLOSED_EVENTS;
else
group = EventGroup.PAST_EVENTS;
if(sortedEventInfos == null || sortedEventInfos.size() == 0)
GenerateSortedLists(true);
else
sortedEventInfos.get(group).add(eventInfo);
if(sortAfterInsert) {
Collections.sort(eventInfos, adDateComparator);
Collections.sort(sortedEventInfos.get(group), adDateComparator);
}
@Override
protected int GetSortedSize1() {
return EventGroup.SIZE;
}
/**
* Will add a new event to the eventInfos and sortedEventInfos, and update if the event already exists
* @return The index of the event in eventInfos. If the event already exists it will return that index. -1 if the json is invalid, ie no _id found
* @param category The 2nd dim of the sorted list
* @return The expected initialisation size
*/
public static int AddEvent(JSONObject json, Context context){
try {
String id = json.getString("_id");
int index = GetEventIndexById(id);
if(index >= 0) {
eventInfos.get(index).UpdateEvent(json);
return index;
}
} catch (JSONException e) {
e.printStackTrace();
return -1;
@Override
protected int GetSortedSize2Expected(int category) {
if(category == EventGroup.HIDDEN_EVENTS)
return EventGroup.HIDDEN_EVENTS_EXP_SIZE;
if(category == EventGroup.CURRENT_EVENTS)
return EventGroup.CURRENT_EVENTS_EXP_SIZE;
if(category == EventGroup.CLOSED_EVENTS)
return EventGroup.CLOSED_EVENTS_EXP_SIZE;
if(category == EventGroup.PAST_EVENTS)
return EventGroup.PAST_EVENTS_EXP_SIZE;
return 0;
}
EventInfo e = new EventInfo(json);
eventInfos.add(e);
AddEventToSorted(e, true);
@Override
public void SaveToCache(Context context){
Settings.SaveEvents(context);
return eventInfos.size() -1;
}
/**
* Will update a given event with the id
* @return true if the event was found and updated
*/
public static boolean UpdateSingleEvent(JSONObject json, @NonNull String eventId){
EventInfo event = GetEventById(eventId);
if(event == null) return false;
event.UpdateEvent(json);
return true;
@Override
public void LoadFromCache(Context context) {
Settings.LoadEvents(context);
}
/**
* Note: Try to use the sorted/eventInfos lists to access by index. Only use this if you are having issues due to the indexes changing from the lists.
* @return The event with the corresponding _id. Returns null if the id was not found.
* @return The category of the sorted list the item fits in, 1st dim
*/
public static EventInfo GetEventById(String id){
int index = GetEventIndexById(id);
if(index >= 0)
return eventInfos.get(index);
return null;
}
@Override
public int GetItemCategory(EventInfo item) {
Date today = Calendar.getInstance().getTime();
/**
*
* @param id The event id
* @return The index in eventInfos (unsorted list)
*/
public static int GetEventIndexById(String id){
if(id == null || id.isEmpty()) return -1;
if(item.time_advertising_start.after(today)) //Determine which group the event is in, by date
return EventGroup.HIDDEN_EVENTS;
else if(item.time_register_end.after(today))
return EventGroup.CURRENT_EVENTS;
else if(item.time_end.after(today))
return EventGroup.CLOSED_EVENTS;
else
return EventGroup.PAST_EVENTS;
for (int i = 0; i < eventInfos.size(); ++i) {
if(eventInfos.get(i)._id.equalsIgnoreCase(id))
return i;
}
//endregion
return -1;
}