Event overview updated

This commit is contained in:
Caesar2011
2018-10-30 02:31:48 +01:00
parent aba6471c1d
commit 92e609babc
9 changed files with 381 additions and 78 deletions

View File

@@ -6,26 +6,40 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import de.sebse.fuplanner.R; import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.KVV.types.Event; 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.services.KVV.types.Modules;
import de.sebse.fuplanner.tools.Triplet;
import de.sebse.fuplanner.tools.UtilsDate; import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.logging.Logger; 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.ItemViewHolder;
import de.sebse.fuplanner.tools.ui.ListViewHolder;
import de.sebse.fuplanner.tools.ui.StringViewHolder; import de.sebse.fuplanner.tools.ui.StringViewHolder;
class ModDetailEventAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { class ModDetailEventAdapter extends RecyclerView.Adapter<CustomViewHolder> {
private static final int TYPE_HEADER = 0; private static final String VALUE_LECTURE = "Class section - Lecture";
private static final int TYPE_ITEM = 1; 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 TYPE_NONE = 0;
private static final int SECTION_PAST = 1; private static final int TYPE_GROUPED = 1;
private static final int TYPE_UNGROUPED = 2;
private Modules.Module mValue; private Modules.Module mValue;
private final ArrayList<Pair<Integer, Integer>> mPositionalData; private final ArrayList<Triplet<Integer, String, Object>> mPositionalData;
private final Logger log = new Logger(this); private final Logger log = new Logger(this);
@@ -41,36 +55,55 @@ class ModDetailEventAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
} }
public void setModule() { public void setModule() {
LinkedHashMap<String, GroupedEvents> listsGrouped = new LinkedHashMap<>();
LinkedHashMap<String, EventList> 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(); mPositionalData.clear();
addPositionalListData(getUpcomingEventsCount(), SECTION_UPCOMING); for (Map.Entry<String, GroupedEvents> value: listsGrouped.entrySet()) {
mPositionalData.add(new Pair<>(TYPE_HEADER, SECTION_PAST)); if (value.getValue().getGroups().size() > 0)
addPositionalListData(getPastEventsCount(), SECTION_PAST); mPositionalData.add(new Triplet<>(TYPE_GROUPED, value.getKey(), value.getValue()));
}
for (Map.Entry<String, EventList> 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(); 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));
}
}
@NonNull @NonNull
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view; View view;
switch (viewType) { switch (viewType) {
case TYPE_HEADER: case TYPE_NONE:
view = LayoutInflater.from(parent.getContext()) view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_all_caption, parent, false); .inflate(R.layout.list_all_no_items, parent, false);
return new StringViewHolder(view); return new CustomViewHolder(view);
case TYPE_ITEM:
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_all_items, parent, false);
return new ItemViewHolder(view);
default: default:
//noinspection ConstantConditions view = LayoutInflater.from(parent.getContext())
return null; .inflate(R.layout.list_all_cardview_list, parent, false);
return new ListViewHolder(view);
} }
} }
@@ -83,51 +116,25 @@ class ModDetailEventAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
} }
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull final CustomViewHolder holder, int position) {
if (mValue == null || position > mPositionalData.size()) if (mValue == null || position > mPositionalData.size())
return; return;
Pair<Integer, Integer> data = mPositionalData.get(position); Triplet<Integer, String, Object> 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) { switch (data.first) {
case TYPE_HEADER: case TYPE_GROUPED:
StringViewHolder h = (StringViewHolder) holder; adapter.setData((GroupedEvents) data.third, h.mView.getContext());
switch (data.second) {
case SECTION_PAST:
h.mString.setText(R.string.past_events);
break; break;
case SECTION_UPCOMING: case TYPE_UNGROUPED:
h.mString.setText(R.string.upcoming_events); adapter.setData((EventList) data.third, h.mView.getContext());
break; break;
} }
break; h.mList.setAdapter(adapter);
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;
} }
} }
@@ -136,15 +143,9 @@ class ModDetailEventAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
return mPositionalData.size(); return mPositionalData.size();
} }
private int getUpcomingEventsCount() { private int getEventsCount() {
if (mValue.events != null) if (mValue.events != null)
return mValue.events.sizeUpcoming(); return mValue.events.size();
return 0;
}
private int getPastEventsCount() {
if (mValue.events != null)
return mValue.events.sizePast();
return 0; return 0;
} }
} }

View File

@@ -0,0 +1,107 @@
package de.sebse.fuplanner.fragments.moddetails;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import androidx.annotation.NonNull;
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.tools.Triplet;
import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.ui.CustomViewHolder;
import de.sebse.fuplanner.tools.ui.ItemViewHolder;
import de.sebse.fuplanner.tools.ui.ListViewHolder;
class ModDetailEventAdapterInner extends RecyclerView.Adapter<ItemViewHolder> {
private final ArrayList<Entry> 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;
}
}
}

View File

@@ -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<Group> 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<Group> getGroups() {
return Collections.unmodifiableList(arrayList);
}
public class Group {
private long firstDate;
private long lastDate;
private ArrayList<Long> 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<Long> 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);
}
}
}

View File

@@ -0,0 +1,14 @@
package de.sebse.fuplanner.tools;
public class Triplet<T, U, V> {
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;
}
}

View File

@@ -46,6 +46,8 @@ public class UtilsDate {
if (context != null && DateFormat.is24HourFormat(context)) if (context != null && DateFormat.is24HourFormat(context))
skeleton = skeleton.replaceAll("h", "H"); 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) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
dateFormat = new SimpleDateFormat(getDateFormat(locale, skeleton)); dateFormat = new SimpleDateFormat(getDateFormat(locale, skeleton));
} else { } else {

View File

@@ -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() + "'";
}
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/string"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
tools:text="Caption"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />
<androidx.recyclerview.widget.RecyclerView
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -68,4 +68,6 @@
<string name="vegetarian">Vegetarisch</string> <string name="vegetarian">Vegetarisch</string>
<string name="bio">Aus biologischem Anbau</string> <string name="bio">Aus biologischem Anbau</string>
<string name="attachment_nr">%1$d. Anhang</string> <string name="attachment_nr">%1$d. Anhang</string>
<string name="event_scale">%1$s, %2$s - %3$s</string>
<string name="except_list">Entfällt: %1$s</string>
</resources> </resources>

View File

@@ -76,4 +76,6 @@
<string name="bio">Organic Food</string> <string name="bio">Organic Food</string>
<string name="msc" translatable="false">MSC</string> <string name="msc" translatable="false">MSC</string>
<string name="attachment_nr">Attachment #%1$d</string> <string name="attachment_nr">Attachment #%1$d</string>
<string name="event_scale">%1$s, %2$s - %3$s</string>
<string name="except_list">Except: %1$s</string>
</resources> </resources>