From 330d76d7a5da72c2816c38f46e8c0450796cbdf0 Mon Sep 17 00:00:00 2001 From: Caesar2011 Date: Mon, 23 Jul 2018 00:32:05 +0200 Subject: [PATCH] Implemented Canteen Browser --- .../java/de/sebse/fuplanner/MainActivity.java | 32 ++- .../fuplanner/fragments/ScheduleFragment.java | 4 +- .../moddetails/ModDetailAnnounceAdapter.java | 4 +- .../ModDetailAssignmentAdapter.java | 4 +- .../moddetails/ModDetailEventAdapter.java | 14 +- .../moddetails/ModDetailOverviewAdapter.java | 18 +- .../services/Canteen/CanteenBrowser.java | 217 ++++++++++++++++++ .../services/Canteen/types/Canteen.java | 122 ++++++++++ .../services/Canteen/types/Canteens.java | 98 ++++++++ .../fuplanner/services/Canteen/types/Day.java | 66 ++++++ .../services/Canteen/types/Meal.java | 119 ++++++++++ .../de/sebse/fuplanner/services/KVV/KVV.java | 4 +- .../fuplanner/services/KVV/KVVModuleList.java | 6 + .../tools/{Conversion.java => DateUtils.java} | 4 +- .../de/sebse/fuplanner/tools/SortedList.java | 118 ++++++++++ .../fuplanner/tools/SortedListCanteen.java | 21 ++ .../sebse/fuplanner/tools/SortedListDay.java | 24 ++ .../sebse/fuplanner/tools/SortedListMeal.java | 20 ++ .../fuplanner/tools/SortedModuleList.java | 3 +- .../fuplanner/tools/ui/weekview/WeekView.java | 4 +- 20 files changed, 869 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/de/sebse/fuplanner/services/Canteen/CanteenBrowser.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteen.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteens.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Day.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Meal.java rename app/src/main/java/de/sebse/fuplanner/tools/{Conversion.java => DateUtils.java} (96%) create mode 100644 app/src/main/java/de/sebse/fuplanner/tools/SortedList.java create mode 100644 app/src/main/java/de/sebse/fuplanner/tools/SortedListCanteen.java create mode 100644 app/src/main/java/de/sebse/fuplanner/tools/SortedListDay.java create mode 100644 app/src/main/java/de/sebse/fuplanner/tools/SortedListMeal.java diff --git a/app/src/main/java/de/sebse/fuplanner/MainActivity.java b/app/src/main/java/de/sebse/fuplanner/MainActivity.java index fa81edd..df448e0 100644 --- a/app/src/main/java/de/sebse/fuplanner/MainActivity.java +++ b/app/src/main/java/de/sebse/fuplanner/MainActivity.java @@ -25,6 +25,8 @@ import de.sebse.fuplanner.fragments.ModulesFragment; import de.sebse.fuplanner.fragments.ScheduleFragment; import de.sebse.fuplanner.fragments.StartupFragment; import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment; +import de.sebse.fuplanner.services.Canteen.CanteenBrowser; +import de.sebse.fuplanner.services.Canteen.types.Canteen; import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth; import de.sebse.fuplanner.services.KVV.KVV; import de.sebse.fuplanner.services.KVV.types.LoginToken; @@ -57,6 +59,7 @@ public class MainActivity extends AppCompatActivity private int fragmentPage = FRAGMENT_NONE; private String fragmentData = ""; + private CanteenBrowser mCanteenBrowser; @Override protected void onCreate(Bundle savedInstanceState) { @@ -97,6 +100,13 @@ public class MainActivity extends AppCompatActivity else checkAndDoLogin(); } + + this.getCanteenBrowser().getCanteens(success -> { + Canteen canteen = success.get(0); + this.getCanteenBrowser().getCanteen(canteen, success1 -> { + this.getCanteenBrowser().getDay(canteen.get(0), log::d, log::e, true); + }, log::e, true); + }, log::e, true); } @Override @@ -204,6 +214,13 @@ public class MainActivity extends AppCompatActivity return this.mKVV; } + public CanteenBrowser getCanteenBrowser() { + if (this.mCanteenBrowser == null) { + this.mCanteenBrowser = new CanteenBrowser(this); + } + return this.mCanteenBrowser; + } + private int getDefaultFragmentAfterLogin() { return FRAGMENT_MODULES; } @@ -271,6 +288,17 @@ public class MainActivity extends AppCompatActivity findViewById(R.id.app_bar_layout).setVisibility(View.GONE); } else { findViewById(R.id.app_bar_layout).setVisibility(View.VISIBLE); + getCanteenBrowser().getCanteens(success -> { + int i = 0; + for (Canteen module : success) { + MenuItem menuItem = mNavigationView.getMenu().add(Menu.NONE, Menu.NONE, 101 + i, module.getName()); + menuItem.setOnMenuItemClickListener(item -> { + log.d("canteen click", module.getId()); + return false; + }); + i++; + } + }, log::e); } // switch to logout if ((fragmentPage != FRAGMENT_STARTUP && fragmentPage != FRAGMENT_LOGIN) && (newFragment == FRAGMENT_STARTUP || newFragment == FRAGMENT_LOGIN)) { @@ -298,8 +326,6 @@ public class MainActivity extends AppCompatActivity mNavigationView.inflateMenu(R.menu.activity_main_drawer_login); mNavigationView.setCheckedItem(R.id.nav_modules); getKVV().getModuleList(success -> { - log.d("Modules.get", success.size()); - //SubMenu moduleMenu = navigationView.getMenu().findItem(R.id.nav_modules).getSubMenu(); int i = 0; for (Iterator it = success.latestSemesterIterator(); it.hasNext(); ) { Modules.Module module = it.next(); @@ -310,7 +336,7 @@ public class MainActivity extends AppCompatActivity }); i++; } - }, error -> log.e("Modules.error", error)); + }, log::e); } if (newFragment == FRAGMENT_MODULES_DETAILS) { getKVV().getModule(newData, success -> { diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java index 9a7f3dc..e6f9bf6 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java @@ -18,7 +18,7 @@ import de.sebse.fuplanner.R; import de.sebse.fuplanner.services.KVV.KVV; import de.sebse.fuplanner.services.KVV.types.Event; import de.sebse.fuplanner.services.KVV.types.Modules; -import de.sebse.fuplanner.tools.Conversion; +import de.sebse.fuplanner.tools.DateUtils; import de.sebse.fuplanner.tools.MainAcitivityListener; import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.ui.weekview.MonthLoader; @@ -143,6 +143,6 @@ public class ScheduleFragment extends Fragment implements MonthLoader.MonthChang Calendar newLastVisibleDay = (Calendar) newFirstVisibleDay.clone(); newLastVisibleDay.add(Calendar.HOUR, 24*mWeekView.getNumberOfVisibleDays()); //mListener.onScheduleFragmentInteraction(newFirstVisibleDay, newLastVisibleDay); - mListener.onTitleTextChange(getResources().getString(R.string.date_scale, Conversion.getModifiedDate(newFirstVisibleDay.getTimeInMillis()), Conversion.getModifiedDate(newLastVisibleDay.getTimeInMillis()))); + mListener.onTitleTextChange(getResources().getString(R.string.date_scale, DateUtils.getModifiedDate(newFirstVisibleDay.getTimeInMillis()), DateUtils.getModifiedDate(newLastVisibleDay.getTimeInMillis()))); } } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java index 1ff6362..4aa5e14 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java @@ -8,7 +8,7 @@ import android.widget.BaseExpandableListAdapter; import de.sebse.fuplanner.R; import de.sebse.fuplanner.services.KVV.types.Announcement; import de.sebse.fuplanner.services.KVV.types.Modules; -import de.sebse.fuplanner.tools.Conversion; +import de.sebse.fuplanner.tools.DateUtils; import de.sebse.fuplanner.tools.ui.ItemViewHolder; import de.sebse.fuplanner.tools.ui.StringViewHolder; @@ -81,7 +81,7 @@ public class ModDetailAnnounceAdapter extends BaseExpandableListAdapter { ItemViewHolder itemHolder = new ItemViewHolder(convertView); itemHolder.mTitle.setText(announce.getTitle()); itemHolder.mSubLeft.setText(announce.getCreatedBy()); - itemHolder.mSubRight.setText(Conversion.getModifiedDateTime(parent.getContext(), announce.getCreatedOn())); + itemHolder.mSubRight.setText(DateUtils.getModifiedDateTime(parent.getContext(), announce.getCreatedOn())); return convertView; } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java index 9e07cf4..39247b8 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java @@ -8,7 +8,7 @@ import android.widget.BaseExpandableListAdapter; import de.sebse.fuplanner.R; import de.sebse.fuplanner.services.KVV.types.Assignment; import de.sebse.fuplanner.services.KVV.types.Modules; -import de.sebse.fuplanner.tools.Conversion; +import de.sebse.fuplanner.tools.DateUtils; import de.sebse.fuplanner.tools.ui.ItemViewHolder; import de.sebse.fuplanner.tools.ui.StringViewHolder; @@ -92,7 +92,7 @@ public class ModDetailAssignmentAdapter extends BaseExpandableListAdapter { itemHolder.mSubLeft.setText(itemHolder.mView.getResources().getText(R.string.open)); else itemHolder.mSubLeft.setText(itemHolder.mView.getResources().getText(R.string.close)); - itemHolder.mSubRight.setText(Conversion.getModifiedDateTime(parent.getContext(), assignment.getDueDate())); + itemHolder.mSubRight.setText(DateUtils.getModifiedDateTime(parent.getContext(), assignment.getDueDate())); return convertView; } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java index 4c7a3c7..6882cfd 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java @@ -13,7 +13,7 @@ import java.util.ArrayList; import de.sebse.fuplanner.R; import de.sebse.fuplanner.services.KVV.types.Event; import de.sebse.fuplanner.services.KVV.types.Modules; -import de.sebse.fuplanner.tools.Conversion; +import de.sebse.fuplanner.tools.DateUtils; import de.sebse.fuplanner.tools.ui.CustomViewHolder; import de.sebse.fuplanner.tools.ui.ItemViewHolder; @@ -114,14 +114,14 @@ public class ModDetailEventAdapter extends RecyclerView.Adapter log.d("Reference to:", SECTION_ANNOUNCEMENT, index)); break; case SECTION_ASSIGNMENT: @@ -152,7 +152,7 @@ public class ModDetailOverviewAdapter extends RecyclerView.Adapter log.d("Reference to:", SECTION_ASSIGNMENT, index)); break; case SECTION_EVENTS: @@ -160,14 +160,14 @@ public class ModDetailOverviewAdapter extends RecyclerView.Adapter callback, final NetworkErrorCallback errorCallback) { + getCanteens(callback, errorCallback, false); + } + + public void getCanteens(final NetworkCallback callback, final NetworkErrorCallback errorCallback, boolean forceRefresh) { + queue.add("list", () -> { + if (this.canteens != null && !forceRefresh) { + callback.onResponse(this.canteens); + queue.next("list"); + return; + } + this.upgradeCanteens(success -> { + if (this.canteens == null) + this.canteens = success; + else + this.canteens.update(success); + this.save(); + callback.onResponse(this.canteens); + queue.next("list"); + }, queue.check("list", errorCallback)); + }); + } + + private void upgradeCanteens(final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + get("https://openmensa.org/api/v2/canteens", null, response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(201101, 403, "No canteen list retrieved!")); + return; + } + Canteens canteens = new Canteens(); + try { + JSONArray json = new JSONArray(body); + + for (int i = 0; i < json.length(); i++) { + JSONObject canteen = json.getJSONObject(i); + int id = canteen.getInt("id"); + String name = canteen.getString("name"); + String city = canteen.getString("city"); + String address = canteen.getString("address"); + JSONArray coords = canteen.getJSONArray("coordinates"); + double lat = 0; + double lng = 0; + if (coords != null) { + lat = coords.getDouble(0); + lng = coords.getDouble(1); + } + for (int cant : Canteens.availableCanteens) { + if (cant == id) { + canteens.addCanteen(id, name, city, address, lat, lng); + break; + } + } + } + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(201102, 403, "Cannot parse canteen list!")); + return; + } + callback.onResponse(canteens); + }, error -> errorCallback.onError(new NetworkError(201103, error.networkResponse.statusCode, "Cannot get canteen list!"))); + } + + public void getCanteen(Canteen canteen, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + getCanteen(canteen, callback, errorCallback, false); + } + + public void getCanteen(Canteen canteen, final NetworkCallback callback, final NetworkErrorCallback errorCallback, boolean forceRefresh) { + String hash = "canteen" + canteen.getId(); + queue.add(hash, () -> { + log.d("getCanteen", canteen.size() > 0 && !forceRefresh); + if (canteen.size() > 0 && !forceRefresh) { + callback.onResponse(canteen); + queue.next(hash); + return; + } + this.upgradeCanteen(canteen, success -> { + canteen.update(success); + this.save(); + callback.onResponse(canteen); + queue.next(hash); + }, queue.check(hash, errorCallback)); + }); + } + + private void upgradeCanteen(Canteen canteen, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + get(String.format("https://openmensa.org/api/v2/canteens/%s/days", canteen.getId()), null, response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(201201, 403, "No day list retrieved!")); + return; + } + try { + JSONArray json = new JSONArray(body); + + for (int i = 0; i < json.length(); i++) { + JSONObject day = json.getJSONObject(i); + String date = day.getString("date"); + boolean closed = day.getBoolean("closed"); + + canteen.addDay(Canteen.keyToCalendar(date), closed); + } + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(201202, 403, "Cannot parse day list!")); + return; + } + callback.onResponse(canteen); + }, error -> errorCallback.onError(new NetworkError(201203, error.networkResponse.statusCode, "Cannot get day list!"))); + } + + public void getDay(Day day, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + getDay(day, callback, errorCallback, false); + } + + public void getDay(Day day, final NetworkCallback callback, final NetworkErrorCallback errorCallback, boolean forceRefresh) { + String hash = "day" + day.getCanteenId() + "@@@" + Canteen.calendarToKey(day.getCalendar()); + queue.add(hash, () -> { + if (day.size() > 0 && !forceRefresh) { + callback.onResponse(day); + queue.next(hash); + return; + } + this.upgradeDay(day, success -> { + day.update(success); + this.save(); + callback.onResponse(day); + queue.next(hash); + }, queue.check(hash, errorCallback)); + }); + } + + private void upgradeDay(Day day, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + get(String.format("https://openmensa.org/api/v2/canteens/%s/days/%s/meals/", day.getCanteenId(), Canteen.calendarToKey(day.getCalendar())), null, response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(201301, 403, "No meal list retrieved!")); + return; + } + try { + JSONArray json = new JSONArray(body); + + for (int i = 0; i < json.length(); i++) { + JSONObject meal = json.getJSONObject(i); + int id = meal.getInt("id"); + String name = meal.getString("name"); + String category = meal.getString("category"); + JSONObject prices = meal.getJSONObject("prices"); + double priceStdnt = 0; + double priceEmply = 0; + double priceOther = 0; + if (prices != null) { + priceStdnt = prices.getDouble("students"); + priceEmply = prices.getDouble("employees"); + priceOther = prices.getDouble("others"); + } + JSONArray noteArray = meal.getJSONArray("notes"); + String[] notes = new String[noteArray.length()]; + for (int j = 0; j < noteArray.length(); j++) { + notes[j] = noteArray.getString(j); + } + + day.addMeal(id, name, category, priceStdnt, priceEmply, priceOther, notes); + } + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(201302, 403, "Cannot parse meal list!")); + return; + } + callback.onResponse(day); + }, error -> errorCallback.onError(new NetworkError(201303, error.networkResponse.statusCode, "Cannot get meal list!"))); + } + + private void save() { + try { + this.canteens.save(this.context); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteen.java b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteen.java new file mode 100644 index 0000000..b4dfb4a --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteen.java @@ -0,0 +1,122 @@ +package de.sebse.fuplanner.services.Canteen.types; + +import android.support.annotation.NonNull; + +import java.io.Serializable; +import java.util.Calendar; +import java.util.Iterator; +import java.util.Locale; + +import de.sebse.fuplanner.tools.SortedListDay; + +public class Canteen implements Serializable, Iterable { + private final int id; + private final String name; + private final String city; + private final String address; + private final double lat; + private final double lng; + private SortedListDay list = new SortedListDay(); + + Canteen(int id, String name, String city, String address, double lat, double lng) { + this.id = id; + this.name = name; + this.city = city; + this.address = address; + this.lat = lat; + this.lng = lng; + } + + private Day getDay(Calendar calendar) { + return this.list.getById(calendar); + } + + public void addDay(Calendar calendar, boolean isClosed) { + Day day = new Day(this, calendar, isClosed); + addDay(day); + } + + private void addDay(@NonNull Day day) { + if (!day.isClosed()) { + this.list.add(day); + } + Calendar minDate = Calendar.getInstance(); + minDate.add(Calendar.DAY_OF_YEAR, -1); + Calendar maxDate = Calendar.getInstance(); + maxDate.add(Calendar.DAY_OF_YEAR, 14); + for (int i = this.list.size() - 1; i >= 0; i--) { + Day d = this.list.get(i); + if (d != null && (d.getCalendar().before(minDate) || d.getCalendar().after(maxDate))) + this.list.remove(i); + } + } + + public int size() { + return this.list.size(); + } + + public Day get(int index) { + return this.list.get(index); + } + + public void update(Canteen canteen) { + SortedListDay oldList = this.list; + this.list = canteen.list; + for (Day oldDay: oldList) { + Day newDay = getDay(oldDay.getCalendar()); + if (newDay != null) newDay.update(oldDay); + } + } + + @NonNull + @Override + public Iterator iterator() { + return this.list.iterator(); + } + + public static String calendarToKey(Calendar calendar) { + int y = calendar.get(Calendar.YEAR); + int m = calendar.get(Calendar.MONTH)+1; + int d = calendar.get(Calendar.DAY_OF_MONTH); + + return String.format(Locale.getDefault(), "%d-%d-%d", y, m, d); + } + + public static Calendar keyToCalendar(String dateString) { + int y = Integer.parseInt(dateString.substring(0, 4)); + int m = Integer.parseInt(dateString.substring(5, 7))-1; + int d = Integer.parseInt(dateString.substring(8, 10)); + Calendar cal = Calendar.getInstance(); + cal.set(y, m, d, 0, 0, 0); + return cal; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public String getCity() { + return city; + } + + public String getAddress() { + return address; + } + + public double getLat() { + return lat; + } + + public double getLng() { + return lng; + } + + @Override + public String toString() { + return id+": "+name+"\n"+list.toString()+"\n"; + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteens.java b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteens.java new file mode 100644 index 0000000..6a2046a --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Canteens.java @@ -0,0 +1,98 @@ +package de.sebse.fuplanner.services.Canteen.types; + +import android.content.Context; +import android.support.annotation.NonNull; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Iterator; + +import de.sebse.fuplanner.tools.SortedListCanteen; + +public class Canteens implements Serializable, Iterable { + public static final int[] availableCanteens = {27, 28, 42}; + private static final String FILE_NAME = "CanteensSaving"; + private SortedListCanteen list = new SortedListCanteen(); + + private Canteen getCanteen(int id) { + return this.list.getById(id); + } + + public void addCanteen(int id, String name, String city, String address, double lat, double lng) { + Canteen canteen = new Canteen(id, name, city, address, lat, lng); + addCanteen(canteen); + } + + private void addCanteen(Canteen canteen) { + this.list.add(canteen); + } + + private int size() { + return this.list.size(); + } + + public Canteen get(int index) { + return this.list.get(index); + } + + public void update(Canteens canteens) { + SortedListCanteen oldList = this.list; + this.list = canteens.list; + for (Canteen oldCanteen: oldList) { + Canteen newCanteen = getCanteen(oldCanteen.getId()); + if (newCanteen != null) newCanteen.update(oldCanteen); + } + } + + @NonNull + @Override + public Iterator iterator() { + return new Iterator() { + int i = 0; + @Override + public boolean hasNext() { + return i < size(); + } + + @Override + public Canteen next() { + return get(i++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("You are not alloed to remove an entry!"); + } + }; + } + + public static Canteens load(Context context) throws IOException, ClassNotFoundException { + FileInputStream fis = context.openFileInput(FILE_NAME); + ObjectInputStream is = new ObjectInputStream(fis); + Canteens modules = (Canteens) is.readObject(); + is.close(); + fis.close(); + return modules; + } + + public void save(Context context) throws IOException { + FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE); + ObjectOutputStream os = new ObjectOutputStream(fos); + os.writeObject(this); + os.close(); + fos.close(); + } + + public void delete(Context context) { + context.deleteFile(FILE_NAME); + } + + @Override + public String toString() { + return this.list.toString(); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Day.java b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Day.java new file mode 100644 index 0000000..ee6b774 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Day.java @@ -0,0 +1,66 @@ +package de.sebse.fuplanner.services.Canteen.types; + +import android.support.annotation.NonNull; + +import java.io.Serializable; +import java.util.Calendar; +import java.util.Iterator; + +import de.sebse.fuplanner.tools.SortedListMeal; + +public class Day implements Serializable, Iterable { + private final int canteenId; + private final Calendar calendar; + private boolean isClosed; + private SortedListMeal list = new SortedListMeal(); + + Day(Canteen canteen, Calendar calendar, boolean isClosed) { + this.canteenId = canteen.getId(); + this.calendar = calendar; + this.isClosed = isClosed; + } + + public Meal getMeal(Integer id) { + return this.list.getById(id); + } + + public void addMeal(int id, String name, String category, double priceStdnt, double priceEmply, double priceOther, String[] notes) { + Meal meal = new Meal(id, name, category, priceStdnt, priceEmply, priceOther, notes); + this.list.add(meal); + } + + public int size() { + return this.list.size(); + } + + public Meal get(int index) { + return this.list.get(index); + } + + public void update(Day day) { + this.list = day.list; + } + + @NonNull + @Override + public Iterator iterator() { + return this.list.iterator(); + } + + public Calendar getCalendar() { + return calendar; + } + + public boolean isClosed() { + return isClosed; + } + + public int getCanteenId() { + return canteenId; + } + + @Override + public String toString() { + return Canteen.calendarToKey(getCalendar())+"\n"+this.list+"\n"; + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Meal.java b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Meal.java new file mode 100644 index 0000000..13fb11d --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/Canteen/types/Meal.java @@ -0,0 +1,119 @@ +package de.sebse.fuplanner.services.Canteen.types; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Meal implements Serializable { + public static final int LIGHT_NONE = 0; + public static final int LIGHT_GREEN = 1; + public static final int LIGHT_YELLOW = 2; + public static final int LIGHT_RED = 3; + public static final int VEGAN_NONE = 0; + public static final int VEGAN_VEGETERIAN = 1; + public static final int VEGAN_VEGAN = 2; + public static final int CERT_NONE = 0b0000; + public static final int CERT_BIO = 0b0001; + public static final int CERT_MSC = 0b0010; + + private final int id; + private final String name; + private final String category; + private final double priceStdnt; + private final double priceEmply; + private final double priceOther; + private final List notes; + private final int light; + private final int vegan; + private final int certificates; + + Meal(int id, String name, String category, double priceStdnt, double priceEmply, double priceOther, String[] notes) { + this.id = id; + this.name = name; + this.category = category; + this.priceStdnt = priceStdnt; + this.priceEmply = priceEmply; + this.priceOther = priceOther; + int light = LIGHT_NONE; + int vegan = VEGAN_NONE; + int certificates = CERT_NONE; + List filteredNotes = new ArrayList<>(); + for (String note : notes) { + switch (note.toLowerCase()) { + case "vegetarisch": + vegan = VEGAN_VEGETERIAN; + break; + case "vegan": + vegan = VEGAN_VEGAN; + break; + case "bio": + certificates += CERT_BIO; + break; + case "msc": + certificates += CERT_MSC; + break; + case "grĂ¼n (ampel)": + light = LIGHT_GREEN; + break; + case "gelb (ampel)": + light = LIGHT_YELLOW; + break; + case "rot (ampel)": + light = LIGHT_RED; + break; + default: + filteredNotes.add(note); + } + } + this.light = light; + this.vegan = vegan; + this.certificates = certificates; + this.notes = Collections.unmodifiableList(filteredNotes); + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public String getCategory() { + return category; + } + + public double getPriceStdnt() { + return priceStdnt; + } + + public double getPriceEmply() { + return priceEmply; + } + + public double getPriceOther() { + return priceOther; + } + + public List getNotes() { + return notes; + } + + public int getLight() { + return light; + } + + public int getVegan() { + return vegan; + } + + public int getCertificates() { + return certificates; + } + + @Override + public String toString() { + return name + " (" + category + ")"; + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/KVV/KVV.java b/app/src/main/java/de/sebse/fuplanner/services/KVV/KVV.java index da583c6..d796585 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/KVV/KVV.java +++ b/app/src/main/java/de/sebse/fuplanner/services/KVV/KVV.java @@ -77,7 +77,7 @@ public class KVV { modules = new KVVModuleList(KVV.this.context, token); addons.put("modules", modules); } - modules.getModule(id, callback, error, forceRefresh); + modules.getModule(id, saveOnCallback(modules, callback), error, forceRefresh); }); } @@ -92,7 +92,7 @@ public class KVV { modules = new KVVModuleList(KVV.this.context, token); addons.put("modules", modules); } - modules.getModuleList(callback, error, forceRefresh); + modules.getModuleList(saveOnCallback(modules, callback), error, forceRefresh); }); } diff --git a/app/src/main/java/de/sebse/fuplanner/services/KVV/KVVModuleList.java b/app/src/main/java/de/sebse/fuplanner/services/KVV/KVVModuleList.java index e5239b7..f7828a3 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/KVV/KVVModuleList.java +++ b/app/src/main/java/de/sebse/fuplanner/services/KVV/KVVModuleList.java @@ -112,9 +112,11 @@ public class KVVModuleList extends HTTPService { modules.addModule(semester, lvNumbers, title, lecturers, type, description, id); } } catch (JSONException e) { + e.printStackTrace(); errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!")); return; } catch (NoSuchFieldException e) { + e.printStackTrace(); errorCallback.onError(new NetworkError(101103, 403, "Cannot parse module list!")); return; } @@ -222,6 +224,7 @@ public class KVVModuleList extends HTTPService { announcements.add(new Announcement(id, title, text, createdBy, createdOn)); } } catch (JSONException e) { + e.printStackTrace(); errorCallback.onError(new NetworkError(101202, 403, "Cannot parse announcements!")); return; } @@ -286,6 +289,7 @@ public class KVVModuleList extends HTTPService { assignments.add(0, new Assignment(id, title, dueTime, gradebookItemName, gradeScale, urls, instructions)); } } catch (JSONException e) { + e.printStackTrace(); errorCallback.onError(new NetworkError(101302, 403, "Cannot parse announcements!")); return; } @@ -341,6 +345,7 @@ public class KVVModuleList extends HTTPService { events.add(new Event(id, type, title, duration, firstTime)); } } catch (JSONException e) { + e.printStackTrace(); errorCallback.onError(new NetworkError(101402, 403, "Cannot parse calendar entries!")); return; } @@ -394,6 +399,7 @@ public class KVVModuleList extends HTTPService { } }catch (JSONException e) { + e.printStackTrace(); errorCallback.onError(new NetworkError(101502, 403, "Cannot parse gradebook for announcements!")); return; } diff --git a/app/src/main/java/de/sebse/fuplanner/tools/Conversion.java b/app/src/main/java/de/sebse/fuplanner/tools/DateUtils.java similarity index 96% rename from app/src/main/java/de/sebse/fuplanner/tools/Conversion.java rename to app/src/main/java/de/sebse/fuplanner/tools/DateUtils.java index 3c8d311..bd755b7 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/Conversion.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/DateUtils.java @@ -13,8 +13,8 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -public class Conversion { - private static Logger log = new Logger("Conversion"); +public class DateUtils { + private static Logger log = new Logger("DateUtils"); @Deprecated public static String getModifiedDateTime(long modified) { diff --git a/app/src/main/java/de/sebse/fuplanner/tools/SortedList.java b/app/src/main/java/de/sebse/fuplanner/tools/SortedList.java new file mode 100644 index 0000000..dbfe5f0 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/SortedList.java @@ -0,0 +1,118 @@ +package de.sebse.fuplanner.tools; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +public abstract class SortedList implements Iterable, Serializable { + + private ArrayList internalList = new ArrayList<>(); + + public void add(T e) { + internalList.add(e); + Collections.sort(internalList, this::compare); + } + + public void remove(int index) { + this.internalList.remove(index); + } + + abstract int compare(T o1, T o2); + + abstract boolean hasIdentifier(T o1, I id); + + abstract boolean hasFilter(T o1, F filter); + + @Nullable + public T get(int i) { + return internalList.get(i); + } + + @Nullable + public T getById(I id) { + for (T item : this.internalList) { + if (hasIdentifier(item, id)) + return item; + } + return null; + } + + public int size() { + return internalList.size(); + } + + @NonNull + @Override + public Iterator iterator() { + return new Iterator() { + private int pos = -1; + @Override + public boolean hasNext() { + return pos+1 < internalList.size(); + } + + @Override + public T next() { + pos++; + if (pos < internalList.size()) + return internalList.get(pos); + return null; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("no changes allowed"); + } + }; + } + + public Iterator filteredIterator(F filter) { + return new Iterator() { + private int index = -1; + private int next = -1; + @Override + public boolean hasNext() { + if (index==next) + predict(); + return next != -1; + } + + @Override + public T next() { + if (index == next) + predict(); + if (next == -1) + return null; + index = next; + return internalList.get(index); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("no changes allowed"); + } + + private void predict() { + int size = internalList.size(); + do { + next++; + } while (next < size && decline(internalList.get(next))); + if (next == size) + next = -1; + } + + private boolean decline(T ob){ + return !hasFilter(ob, filter); + } + }; + } + + @Override + public String toString() { + return this.internalList.toString(); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/SortedListCanteen.java b/app/src/main/java/de/sebse/fuplanner/tools/SortedListCanteen.java new file mode 100644 index 0000000..fe80cf6 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/SortedListCanteen.java @@ -0,0 +1,21 @@ +package de.sebse.fuplanner.tools; + +import de.sebse.fuplanner.services.Canteen.types.Canteen; + +public class SortedListCanteen extends SortedList { + @Override + int compare(Canteen o1, Canteen o2) { + // TODO correct implementation + return Integer.compare(o1.getId(), o2.getId()); + } + + @Override + boolean hasIdentifier(Canteen o1, Integer id) { + return o1.getId() == id; + } + + @Override + boolean hasFilter(Canteen o1, String filter) { + return o1.getCity().equals(filter); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/SortedListDay.java b/app/src/main/java/de/sebse/fuplanner/tools/SortedListDay.java new file mode 100644 index 0000000..88a17aa --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/SortedListDay.java @@ -0,0 +1,24 @@ +package de.sebse.fuplanner.tools; + +import java.util.Calendar; + +import de.sebse.fuplanner.services.Canteen.types.Canteen; +import de.sebse.fuplanner.services.Canteen.types.Day; + +public class SortedListDay extends SortedList { + @Override + int compare(Day o1, Day o2) { + // TODO correct implementation + return Canteen.calendarToKey(o1.getCalendar()).compareTo(Canteen.calendarToKey(o2.getCalendar())); + } + + @Override + boolean hasIdentifier(Day o1, Calendar id) { + return Canteen.calendarToKey(o1.getCalendar()).equals(Canteen.calendarToKey(id)); + } + + @Override + boolean hasFilter(Day o1, String filter) { + return false; + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/SortedListMeal.java b/app/src/main/java/de/sebse/fuplanner/tools/SortedListMeal.java new file mode 100644 index 0000000..9a3cbac --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/SortedListMeal.java @@ -0,0 +1,20 @@ +package de.sebse.fuplanner.tools; + +import de.sebse.fuplanner.services.Canteen.types.Meal; + +public class SortedListMeal extends SortedList { + @Override + int compare(Meal o1, Meal o2) { + return Integer.compare(o1.getId(), o2.getId()); + } + + @Override + boolean hasIdentifier(Meal o1, Integer id) { + return o1.getId() == id; + } + + @Override + boolean hasFilter(Meal o1, String filter) { + return o1.getCategory().equals(filter); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/SortedModuleList.java b/app/src/main/java/de/sebse/fuplanner/tools/SortedModuleList.java index bf56d55..0d3f5c3 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/SortedModuleList.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/SortedModuleList.java @@ -13,7 +13,7 @@ import de.sebse.fuplanner.services.KVV.types.Modules; public class SortedModuleList extends AbstractList implements Serializable { - private ArrayList internalList = new ArrayList(); + private ArrayList internalList = new ArrayList<>(); // Note that add(E e) in AbstractList is calling this one @Override @@ -27,7 +27,6 @@ public class SortedModuleList extends AbstractList implements Se }); } - @Deprecated @Override public Modules.Module get(int i) { return internalList.get(i); diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/weekview/WeekView.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/weekview/WeekView.java index 7e6a41e..7eb522d 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/ui/weekview/WeekView.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/weekview/WeekView.java @@ -47,7 +47,7 @@ import java.util.List; import java.util.Locale; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.tools.Conversion; +import de.sebse.fuplanner.tools.DateUtils; import static de.sebse.fuplanner.tools.ui.weekview.WeekViewUtil.daysBetween; import static de.sebse.fuplanner.tools.ui.weekview.WeekViewUtil.getPassedMinutesInDay; @@ -1619,7 +1619,7 @@ public class WeekView extends View { @Override public String interpretDate(Calendar date) { try { - return Conversion.getModifiedDate(getContext(), date.getTimeInMillis(), "EEE dd.M").toUpperCase(); + return DateUtils.getModifiedDate(getContext(), date.getTimeInMillis(), "EEE dd.M").toUpperCase(); } catch (Exception e) { e.printStackTrace(); return "";