From 92e609babc04caa6f76dbae8bfab0aad640f7525 Mon Sep 17 00:00:00 2001 From: Caesar2011 Date: Tue, 30 Oct 2018 02:31:48 +0100 Subject: [PATCH] Event overview updated --- .../moddetails/ModDetailEventAdapter.java | 157 +++++++++--------- .../ModDetailEventAdapterInner.java | 107 ++++++++++++ .../services/KVV/types/GroupedEvents.java | 128 ++++++++++++++ .../de/sebse/fuplanner/tools/Triplet.java | 14 ++ .../de/sebse/fuplanner/tools/UtilsDate.java | 2 + .../fuplanner/tools/ui/ListViewHolder.java | 22 +++ .../res/layout/list_all_cardview_list.xml | 25 +++ app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 9 files changed, 381 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapterInner.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/KVV/types/GroupedEvents.java create mode 100644 app/src/main/java/de/sebse/fuplanner/tools/Triplet.java create mode 100644 app/src/main/java/de/sebse/fuplanner/tools/ui/ListViewHolder.java create mode 100644 app/src/main/res/layout/list_all_cardview_list.xml 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 960682c..c61c38b 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 @@ -6,26 +6,40 @@ import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import de.sebse.fuplanner.R; import de.sebse.fuplanner.services.KVV.types.Event; +import de.sebse.fuplanner.services.KVV.types.EventList; +import de.sebse.fuplanner.services.KVV.types.GroupedEvents; import de.sebse.fuplanner.services.KVV.types.Modules; +import de.sebse.fuplanner.tools.Triplet; import de.sebse.fuplanner.tools.UtilsDate; import de.sebse.fuplanner.tools.logging.Logger; +import de.sebse.fuplanner.tools.ui.CustomViewHolder; import de.sebse.fuplanner.tools.ui.ItemViewHolder; +import de.sebse.fuplanner.tools.ui.ListViewHolder; import de.sebse.fuplanner.tools.ui.StringViewHolder; -class ModDetailEventAdapter extends RecyclerView.Adapter { - private static final int TYPE_HEADER = 0; - private static final int TYPE_ITEM = 1; +class ModDetailEventAdapter extends RecyclerView.Adapter { + private static final String VALUE_LECTURE = "Class section - Lecture"; + private static final String VALUE_TUTORIAL = "Class section - Small Group"; + private static final String VALUE_EXAM = "Exam"; + private static final String VALUE_DEADLINE = "Deadline"; + private static final String VALUE_OTHER = "Other"; + private static final String[] VALUES_GROUPED = {VALUE_LECTURE, VALUE_TUTORIAL}; + private static final String[] VALUES_UNGROUPED = {VALUE_EXAM, VALUE_DEADLINE}; - private static final int SECTION_UPCOMING = 0; - private static final int SECTION_PAST = 1; + private static final int TYPE_NONE = 0; + private static final int TYPE_GROUPED = 1; + private static final int TYPE_UNGROUPED = 2; private Modules.Module mValue; - private final ArrayList> mPositionalData; + private final ArrayList> mPositionalData; private final Logger log = new Logger(this); @@ -41,36 +55,55 @@ class ModDetailEventAdapter extends RecyclerView.Adapter(TYPE_HEADER, SECTION_PAST)); - addPositionalListData(getPastEventsCount(), SECTION_PAST); - - this.notifyDataSetChanged(); - } - - private void addPositionalListData(int count, int category) { - for (int i = 0; i < count; i++) { - mPositionalData.add(new Pair<>(TYPE_ITEM, category+1024*i)); + LinkedHashMap listsGrouped = new LinkedHashMap<>(); + LinkedHashMap listsUngrouped = new LinkedHashMap<>(); + for (String value : VALUES_GROUPED) listsGrouped.put(value, new GroupedEvents()); + for (String value : VALUES_UNGROUPED) listsUngrouped.put(value, new EventList()); + listsUngrouped.put(VALUE_OTHER, new EventList()); + for (int i = 0; i < getEventsCount(); i++) { + assert mValue.events != null; + Event event = mValue.events.get(i); + String type = event.getType(); + GroupedEvents groupedEvents = listsGrouped.get(type); + if (groupedEvents != null) { + groupedEvents.add(event); + } else { + EventList ungroupedEvents = listsUngrouped.get(type); + if (ungroupedEvents == null) { + ungroupedEvents = listsUngrouped.get(VALUE_OTHER); + } + assert ungroupedEvents != null; + ungroupedEvents.add(event); + } } + + mPositionalData.clear(); + for (Map.Entry value: listsGrouped.entrySet()) { + if (value.getValue().getGroups().size() > 0) + mPositionalData.add(new Triplet<>(TYPE_GROUPED, value.getKey(), value.getValue())); + } + for (Map.Entry value: listsUngrouped.entrySet()) { + if (value.getValue().size() > 0) + mPositionalData.add(new Triplet<>(TYPE_UNGROUPED, value.getKey(), value.getValue())); + } + if (mPositionalData.size() == 0) + mPositionalData.add(new Triplet<>(TYPE_NONE, null, null)); + this.notifyDataSetChanged(); } @NonNull @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; switch (viewType) { - case TYPE_HEADER: + case TYPE_NONE: view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.list_all_caption, parent, false); - return new StringViewHolder(view); - case TYPE_ITEM: - view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.list_all_items, parent, false); - return new ItemViewHolder(view); + .inflate(R.layout.list_all_no_items, parent, false); + return new CustomViewHolder(view); default: - //noinspection ConstantConditions - return null; + view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_all_cardview_list, parent, false); + return new ListViewHolder(view); } } @@ -83,51 +116,25 @@ class ModDetailEventAdapter extends RecyclerView.Adapter mPositionalData.size()) return; - Pair data = mPositionalData.get(position); - switch (data.first) { - case TYPE_HEADER: - StringViewHolder h = (StringViewHolder) holder; - switch (data.second) { - case SECTION_PAST: - h.mString.setText(R.string.past_events); - break; - case SECTION_UPCOMING: - h.mString.setText(R.string.upcoming_events); - break; - } - break; - case TYPE_ITEM: - int section = data.second % 1024; - int index = data.second / 1024; - ItemViewHolder i = (ItemViewHolder) holder; - Event event = null; - switch (section) { - case SECTION_UPCOMING: - event = mValue.events.getUpcoming(index); - break; - case SECTION_PAST: - event = mValue.events.getPast(index); - break; - } - //noinspection ConstantConditions - i.mTitle.setText(event.getTitle()); - i.mSubLeft.setText(event.getType()); - String start, end; - if (UtilsDate.dateEquals(event.getStartDate(), System.currentTimeMillis())) - start = UtilsDate.getModifiedTime(i.mView.getContext(), event.getStartDate()); - else - start = UtilsDate.getModifiedDateTime(i.mView.getContext(), event.getStartDate()); - if (UtilsDate.dateEquals(event.getStartDate(), event.getEndDate())) - end = UtilsDate.getModifiedTime(i.mView.getContext(), event.getEndDate()); - else - end = UtilsDate.getModifiedDateTime(i.mView.getContext(), event.getEndDate()); - i.mSubRight.setText(i.mView.getResources().getString(R.string.date_scale, - start, end - )); - break; + Triplet data = mPositionalData.get(position); + if (data.first != TYPE_NONE) { + ListViewHolder h; + ModDetailEventAdapterInner adapter; + h = (ListViewHolder) holder; + adapter = new ModDetailEventAdapterInner(); + h.mString.setText(data.second); + switch (data.first) { + case TYPE_GROUPED: + adapter.setData((GroupedEvents) data.third, h.mView.getContext()); + break; + case TYPE_UNGROUPED: + adapter.setData((EventList) data.third, h.mView.getContext()); + break; + } + h.mList.setAdapter(adapter); } } @@ -136,15 +143,9 @@ class ModDetailEventAdapter extends RecyclerView.Adapter { + private final ArrayList mPositionalData; + + ModDetailEventAdapterInner() { + mPositionalData = new ArrayList<>(); + } + + public void setData(GroupedEvents events, final Context context) { + mPositionalData.clear(); + for (GroupedEvents.Group group : events.getGroups()) { + long firstDateTime = group.getFirstDate()+group.getStartTime(); + long lastDateTime = group.getLastDate()+group.getStartTime()+group.getDuration(); + String start, end, weekday, startTime, endTime; + StringBuilder excepts = null; + start = UtilsDate.getModifiedDate(firstDateTime); + end = UtilsDate.getModifiedDate(lastDateTime); + weekday = UtilsDate.getModifiedDate(context, firstDateTime, "E"); + startTime = UtilsDate.getModifiedTime(context, firstDateTime); + endTime = UtilsDate.getModifiedTime(context, lastDateTime); + for (long skippedDate : group.getSkippedDates()) { + if (excepts == null) { + excepts = new StringBuilder(UtilsDate.getModifiedDate(skippedDate)); + } else { + excepts.append(", ").append(UtilsDate.getModifiedDate(skippedDate)); + } + } + mPositionalData.add(new Entry( + context.getString(R.string.event_scale, weekday, startTime, endTime), + context.getString(R.string.date_scale, start, end), + excepts != null ? context.getString(R.string.except_list, excepts.toString()) : "")); + } + this.notifyDataSetChanged(); + } + + public void setData(EventList events, final Context context) { + mPositionalData.clear(); + for (Event event : events) { + String date; + String start, end; + if (UtilsDate.dateEquals(event.getStartDate(), System.currentTimeMillis())) + start = UtilsDate.getModifiedTime(context, event.getStartDate()); + else + start = UtilsDate.getModifiedDateTime(context, event.getStartDate()); + if (UtilsDate.dateEquals(event.getStartDate(), event.getEndDate())) + end = UtilsDate.getModifiedTime(context, event.getEndDate()); + else + end = UtilsDate.getModifiedDateTime(context, event.getEndDate()); + date = context.getString(R.string.date_scale, start, end); + mPositionalData.add(new Entry(event.getTitle(), date, "")); + } + this.notifyDataSetChanged(); + } + + @NonNull + @Override + public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_all_items, parent, false); + return new ItemViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull final ItemViewHolder holder, int position) { + holder.mTitle.setText(mPositionalData.get(position).title); + holder.mSubLeft.setText(mPositionalData.get(position).subtitleLeft); + holder.mSubRight.setText(mPositionalData.get(position).subtitleRight); + } + + @Override + public int getItemCount() { + return mPositionalData.size(); + } + + private class Entry { + private String title; + private String subtitleLeft; + private String subtitleRight; + + private Entry(String title, String subtitleLeft, String subtitleRight) { + this.title = title; + this.subtitleLeft = subtitleLeft; + this.subtitleRight = subtitleRight; + } + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/KVV/types/GroupedEvents.java b/app/src/main/java/de/sebse/fuplanner/services/KVV/types/GroupedEvents.java new file mode 100644 index 0000000..1ffb9cf --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/KVV/types/GroupedEvents.java @@ -0,0 +1,128 @@ +package de.sebse.fuplanner.services.KVV.types; + + +import android.annotation.SuppressLint; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +import androidx.annotation.NonNull; +import de.sebse.fuplanner.tools.logging.Logger; + +public class GroupedEvents { + private ArrayList arrayList = new ArrayList<>(); + private Logger log = new Logger(this); + + public void add(Event event) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(event.getStartDate()); + long dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); + for (Group group : arrayList) { + if (group.add(event)) { + return; + } + } + arrayList.add(new Group(event)); + } + + public List getGroups() { + return Collections.unmodifiableList(arrayList); + } + + public class Group { + private long firstDate; + private long lastDate; + private ArrayList skippedDates; + + private int dayOfWeek; + private long startTime; + private long duration; + + private Group(Event event) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(event.getStartDate()); + dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); + startTime = calendar.get(Calendar.HOUR_OF_DAY)*3600000+calendar.get(Calendar.MINUTE)*60000+calendar.get(Calendar.SECOND)*1000+calendar.get(Calendar.MILLISECOND); + duration = event.getEndDate()-event.getStartDate(); + + skippedDates = new ArrayList<>(); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + firstDate = calendar.getTimeInMillis(); + lastDate = firstDate; + } + + private boolean add(Event event) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(event.getStartDate()); + int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); + int startTime = calendar.get(Calendar.HOUR_OF_DAY)*3600000+calendar.get(Calendar.MINUTE)*60000+calendar.get(Calendar.SECOND)*1000+calendar.get(Calendar.MILLISECOND); + long length = event.getEndDate()-event.getStartDate(); + if (this.dayOfWeek != dayOfWeek || this.startTime != startTime || this.duration != length) + return false; + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + long date = calendar.getTimeInMillis(); + if (date < firstDate) { + firstDate = addDays(firstDate, -7); + while (firstDate > date) { + skippedDates.add(firstDate); + firstDate = addDays(firstDate, -7); + } + } else if (date > lastDate) { + lastDate = addDays(lastDate, 7); + while (lastDate < date) { + skippedDates.add(lastDate); + lastDate = addDays(lastDate, 7); + } + } else { + skippedDates.remove(date); + } + return true; + } + + private long addDays(long timeInMillis, int days) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(timeInMillis); + calendar.add(Calendar.DAY_OF_YEAR, days); + return calendar.getTimeInMillis(); + } + + public long getFirstDate() { + return firstDate; + } + + public long getLastDate() { + return lastDate; + } + + public List getSkippedDates() { + return Collections.unmodifiableList(skippedDates); + } + + public int getDayOfWeek() { + return dayOfWeek; + } + + public long getStartTime() { + return startTime; + } + + public long getDuration() { + return duration; + } + + @SuppressLint("DefaultLocale") + @NonNull + @Override + public String toString() { + return String.format("%d - %d - %d - %s", dayOfWeek, startTime, duration, skippedDates); + } + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/Triplet.java b/app/src/main/java/de/sebse/fuplanner/tools/Triplet.java new file mode 100644 index 0000000..84098cc --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/Triplet.java @@ -0,0 +1,14 @@ +package de.sebse.fuplanner.tools; + +public class Triplet { + + public final T first; + public final U second; + public final V third; + + public Triplet(T first, U second, V third) { + this.first = first; + this.second = second; + this.third = third; + } +} \ No newline at end of file diff --git a/app/src/main/java/de/sebse/fuplanner/tools/UtilsDate.java b/app/src/main/java/de/sebse/fuplanner/tools/UtilsDate.java index e631a87..b0262de 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/UtilsDate.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/UtilsDate.java @@ -46,6 +46,8 @@ public class UtilsDate { if (context != null && DateFormat.is24HourFormat(context)) skeleton = skeleton.replaceAll("h", "H"); + if (context != null && !DateFormat.is24HourFormat(context)) + skeleton = skeleton.replaceAll("H", "h"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { dateFormat = new SimpleDateFormat(getDateFormat(locale, skeleton)); } else { diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/ListViewHolder.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/ListViewHolder.java new file mode 100644 index 0000000..9c7534f --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/ListViewHolder.java @@ -0,0 +1,22 @@ +package de.sebse.fuplanner.tools.ui; + +import android.view.View; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; +import de.sebse.fuplanner.R; + +public class ListViewHolder extends StringViewHolder { + public final RecyclerView mList; + + public ListViewHolder(View view) { + super(view); + mList = view.findViewById(R.id.list); + } + + @Override + public String toString() { + return super.toString() + " '" + mString.getText() + "'"; + } +} diff --git a/app/src/main/res/layout/list_all_cardview_list.xml b/app/src/main/res/layout/list_all_cardview_list.xml new file mode 100644 index 0000000..595ddb5 --- /dev/null +++ b/app/src/main/res/layout/list_all_cardview_list.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1b9e53a..2aa098c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -68,4 +68,6 @@ Vegetarisch Aus biologischem Anbau %1$d. Anhang + %1$s, %2$s - %3$s + Entfällt: %1$s \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 279b1b7..d120b73 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,4 +76,6 @@ Organic Food MSC Attachment #%1$d + %1$s, %2$s - %3$s + Except: %1$s