[UI/Agenda] Rewrite agenda in Kotlin and add lesson change counters.

This commit is contained in:
Kacper Ziubryniewicz 2020-01-26 22:20:46 +01:00
parent 5bf181b6d1
commit 16bf478d1a
12 changed files with 421 additions and 538 deletions

View File

@ -46,24 +46,33 @@ interface TimetableDao {
@Query("DELETE FROM timetable WHERE profileId = :profileId AND type != -1 AND ((type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom))")
fun clearFromDate(profileId: Int, dateFrom: Date)
@Query("DELETE FROM timetable WHERE profileId = :profileId AND type != -1 AND ((type != 3 AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate <= :dateTo))")
fun clearToDate(profileId: Int, dateTo: Date)
@Query("DELETE FROM timetable WHERE profileId = :profileId AND type != -1 AND ((type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo))")
fun clearBetweenDates(profileId: Int, dateFrom: Date, dateTo: Date)
@Query("""
$QUERY
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
WHERE timetable.profileId = :profileId AND type != -1 AND type != 0
ORDER BY id, type
""")
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
fun getAllChangesNow(profileId: Int): List<Lesson>
@Query("""
$QUERY
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
ORDER BY id, type
""")
fun getForDateNow(profileId: Int, date: Date) : List<LessonFull>
fun getForDate(profileId: Int, date: Date): LiveData<List<LessonFull>>
@Query("""
$QUERY
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
ORDER BY id, type
""")
fun getForDateNow(profileId: Int, date: Date): List<LessonFull>
@Query("""
$QUERY
@ -71,7 +80,7 @@ interface TimetableDao {
ORDER BY id, type
LIMIT 1
""")
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull?>
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long): LiveData<LessonFull?>
@Query("""
$QUERY
@ -86,21 +95,21 @@ interface TimetableDao {
WHERE (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)
ORDER BY profileId, id, type
""")
fun getBetweenDatesNow(dateFrom: Date, dateTo: Date) : List<LessonFull>
fun getBetweenDatesNow(dateFrom: Date, dateTo: Date): List<LessonFull>
@Query("""
$QUERY
WHERE (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)
ORDER BY profileId, id, type
""")
fun getBetweenDates(dateFrom: Date, dateTo: Date) : LiveData<List<LessonFull>>
fun getBetweenDates(dateFrom: Date, dateTo: Date): LiveData<List<LessonFull>>
@Query("""
$QUERY
WHERE timetable.profileId = :profileId AND timetable.id = :lessonId
ORDER BY id, type
""")
fun getByIdNow(profileId: Int, lessonId: Long) : LessonFull?
fun getByIdNow(profileId: Int, lessonId: Long): LessonFull?
@Query("""
$QUERY

View File

@ -10,6 +10,8 @@ import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.Index;
import java.util.Calendar;
import pl.szczodrzynski.edziennik.data.db.full.EventFull;
import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.edziennik.utils.models.Time;
@ -96,6 +98,27 @@ public class Event {
return new EventFull(this, metadata);
}
@Ignore
public Calendar getStartTimeCalendar() {
Calendar c = Calendar.getInstance();
c.set(
eventDate.year,
eventDate.month - 1,
eventDate.day,
(startTime == null) ? 0 : startTime.hour,
(startTime == null) ? 0 : startTime.minute,
(startTime == null) ? 0 : startTime.second
);
return c;
}
@Ignore
public Calendar getEndTimeCalendar() {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(getStartTimeCalendar().getTimeInMillis() + (45 * 60 * 1000));
return c;
}
@Override
public Event clone() {
Event event = new Event(

View File

@ -1,42 +1,57 @@
package pl.szczodrzynski.edziennik.ui.dialogs.teacherabsence
import android.content.Context
import android.view.View
import androidx.databinding.DataBindingUtil
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogTeacherAbsenceListBinding
import pl.szczodrzynski.edziennik.utils.models.Date
class TeacherAbsenceDialog(val context: Context) {
class TeacherAbsenceDialog(
val activity: AppCompatActivity,
val profileId: Int,
val date: Date,
val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null
) {
companion object {
private const val TAG = "TeacherAbsenceDialog"
}
private val app by lazy { activity.application as App }
val profileId: Int = App.profileId
private lateinit var b: DialogTeacherAbsenceListBinding
private lateinit var dialog: AlertDialog
fun show(app: App, date: Date) {
val dialog = MaterialDialog.Builder(context)
.title(date.formattedString)
.customView(R.layout.dialog_teacher_absence_list, false)
.positiveText(R.string.close)
.autoDismiss(false)
.onPositive { dialog, _ -> dialog.dismiss()}
.show()
init { run {
if (activity.isFinishing)
return@run
val customView: View = dialog.customView ?: return
b = DataBindingUtil.bind(customView) ?: return
b = DialogTeacherAbsenceListBinding.inflate(activity.layoutInflater)
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(date.formattedString)
.setView(b.root)
.setPositiveButton(R.string.close) { dialog, _ -> dialog.dismiss() }
.setOnDismissListener {
onDismissListener?.invoke(TAG)
}
.create()
b.teacherAbsenceView.setHasFixedSize(true)
b.teacherAbsenceView.layoutManager = LinearLayoutManager(context)
b.teacherAbsenceView.layoutManager = LinearLayoutManager(activity)
app.db.teacherAbsenceDao().getAllByDateFull(profileId, date).observe(context as LifecycleOwner, Observer { absenceList ->
val adapter = TeacherAbsenceAdapter(context, date, absenceList)
app.db.teacherAbsenceDao().getAllByDateFull(profileId, date).observe(activity as LifecycleOwner, Observer { absenceList ->
val adapter = TeacherAbsenceAdapter(activity, date, absenceList)
b.teacherAbsenceView.adapter = adapter
b.teacherAbsenceView.visibility = View.VISIBLE
})
}
dialog.show()
}}
}

View File

@ -1,470 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.agenda;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import com.applandeo.materialcalendarview.CalendarView;
import com.applandeo.materialcalendarview.EventDay;
import com.github.tibolte.agendacalendarview.AgendaCalendarView;
import com.github.tibolte.agendacalendarview.CalendarPickerController;
import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent;
import com.github.tibolte.agendacalendarview.models.CalendarEvent;
import com.github.tibolte.agendacalendarview.models.IDayItem;
import com.mikepenz.iconics.IconicsColor;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.iconics.IconicsSize;
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.MainActivity;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.db.full.EventFull;
import pl.szczodrzynski.edziennik.data.db.full.TeacherAbsenceFull;
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding;
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.day.DayDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.lessonchange.LessonChangeDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.teacherabsence.TeacherAbsenceDialog;
import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEvent;
import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEventRenderer;
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceCounter;
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEvent;
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEventRenderer;
import pl.szczodrzynski.edziennik.utils.Colors;
import pl.szczodrzynski.edziennik.utils.Themes;
import pl.szczodrzynski.edziennik.utils.Utils;
import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_EVENT;
import static pl.szczodrzynski.edziennik.data.db.entity.Profile.AGENDA_CALENDAR;
import static pl.szczodrzynski.edziennik.data.db.entity.Profile.AGENDA_DEFAULT;
import static pl.szczodrzynski.edziennik.utils.Utils.intToStr;
public class AgendaFragment extends Fragment {
private App app = null;
private MainActivity activity = null;
private FragmentAgendaDefaultBinding b_default = null;
private FragmentAgendaCalendarBinding b_calendar = null;
private int viewType = AGENDA_DEFAULT;
private Date actualDate = null;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
activity = (MainActivity) getActivity();
if (getActivity() == null || getContext() == null)
return null;
app = (App) activity.getApplication();
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
if (app.getProfile() == null)
return inflater.inflate(R.layout.fragment_loading, container, false);
// activity, context and profile is valid
viewType = app.getConfig().forProfile().getUi().getAgendaViewType();
if (viewType == AGENDA_DEFAULT) {
b_default = DataBindingUtil.inflate(inflater, R.layout.fragment_agenda_default, container, false);
return b_default.getRoot();
}
else {
b_calendar = DataBindingUtil.inflate(inflater, R.layout.fragment_agenda_calendar, container, false);
return b_calendar.getRoot();
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
if (app == null || activity == null || b_default == null && b_calendar == null || !isAdded())
return;
activity.getBottomSheet().prependItems(
new BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_add_event)
.withDescription(R.string.menu_add_event_desc)
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
.withOnClickListener(v3 -> {
activity.getBottomSheet().close();
new EventManualDialog(
activity,
App.Companion.getProfileId(),
null,
actualDate,
null,
null,
null,
null,
null
);
}),
new BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_agenda_change_view)
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar_outline : CommunityMaterial.Icon.cmd_format_list_bulleted_square)
.withOnClickListener(v3 -> {
activity.getBottomSheet().close();
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
app.getConfig().forProfile().getUi().setAgendaViewType(viewType);
activity.reloadTarget();
}),
new BottomSheetSeparatorItem(true),
new BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_mark_as_read)
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
.withOnClickListener(v3 -> {
activity.getBottomSheet().close();
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_EVENT, true));
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
})
);
activity.getNavView().bottomBar.setFabEnable(true);
activity.getNavView().bottomBar.setFabExtendedText(getString(R.string.add));
activity.getNavView().bottomBar.setFabIcon(CommunityMaterial.Icon2.cmd_plus);
activity.getNavView().setFabOnClickListener(v -> new EventManualDialog(
activity,
App.Companion.getProfileId(),
null,
actualDate,
null,
null,
null,
null,
null
));
activity.gainAttention();
activity.gainAttentionFAB();
if (viewType == AGENDA_DEFAULT) {
createDefaultAgendaView();
}
else {
createCalendarAgendaView();
}
}
private void createDefaultAgendaView() {
List<Integer> unreadEventDates = new ArrayList<>();
final Handler handler = new Handler();
handler.postDelayed(() -> AsyncTask.execute(() -> {
if (app == null || activity == null || b_default == null || !isAdded())
return;
List<CalendarEvent> eventList = new ArrayList<>();
/* List<LessonChangeCounter> lessonChangeCounters = app.db.lessonChangeDao().getLessonChangeCountersNow(App.profileId);
for (LessonChangeCounter counter : lessonChangeCounters) {
Calendar startTime = Calendar.getInstance();
Calendar endTime = Calendar.getInstance();
if (counter.lessonChangeDate == null) {
continue;
}
startTime.set(counter.lessonChangeDate.year, counter.lessonChangeDate.month - 1, counter.lessonChangeDate.day, 10, 0, 0);
endTime.setTimeInMillis(startTime.getTimeInMillis() + (1000 * 60 * 45));
eventList.add(new LessonChangeEvent(
counter.lessonChangeDate.getInMillis(),
0xff78909c,
Colors.legibleTextColor(0xff78909c),
startTime,
endTime,
counter.profileId,
counter.lessonChangeDate,
counter.lessonChangeCount
));
} TODO: Implement new timetable lesson changes */
if (app.getProfile().getStudentData("showTeacherAbsences", true)) {
List<TeacherAbsenceFull> teacherAbsenceList = App.db.teacherAbsenceDao().getAllFullNow(App.Companion.getProfileId());
List<TeacherAbsenceCounter> teacherAbsenceCounters = new ArrayList<>();
for (TeacherAbsenceFull absence : teacherAbsenceList) {
for (Date date = absence.getDateFrom().clone(); date.compareTo(absence.getDateTo()) < 1; date.stepForward(0, 0, 1)) {
boolean counterFound = false;
for (TeacherAbsenceCounter counter : teacherAbsenceCounters) {
if (counter.getTeacherAbsenceDate().compareTo(date) == 0) {
counter.setTeacherAbsenceCount(counter.getTeacherAbsenceCount() + 1);
counterFound = true;
break;
}
}
if (!counterFound) {
teacherAbsenceCounters.add(new TeacherAbsenceCounter(date.clone(), 1));
}
}
}
for (TeacherAbsenceCounter counter : teacherAbsenceCounters) {
Calendar startTime = Calendar.getInstance();
Calendar endTime = Calendar.getInstance();
Date date = counter.getTeacherAbsenceDate();
startTime.set(date.year, date.month - 1, date.day, 10, 0, 0);
endTime.setTimeInMillis(startTime.getTimeInMillis() + (1000 * 60 * 45));
eventList.add(new TeacherAbsenceEvent(
date.getInMillis(),
0xffff1744,
Colors.legibleTextColor(0xffff1744),
startTime,
endTime,
App.Companion.getProfileId(),
date,
counter.getTeacherAbsenceCount()
));
}
}
List<EventFull> events = App.db.eventDao().getAllNow(App.Companion.getProfileId());
for (EventFull event : events) {
Calendar startTime = Calendar.getInstance();
Calendar endTime = Calendar.getInstance();
if (event.eventDate == null)
continue;
startTime.set(
event.eventDate.year,
event.eventDate.month - 1,
event.eventDate.day,
event.startTime == null ? 0 : event.startTime.hour,
event.startTime == null ? 0 : event.startTime.minute,
event.startTime == null ? 0 : event.startTime.second
);
endTime.setTimeInMillis(startTime.getTimeInMillis() + (1000 * 60 * 45));
eventList.add(new BaseCalendarEvent(event.typeName + " - " + event.topic,
"",
(event.startTime == null ? getString(R.string.agenda_event_all_day) : event.startTime.getStringHM()) +
Utils.bs(", ", event.subjectLongName) +
Utils.bs(", ", event.teacherFullName) +
Utils.bs(", ", event.teamName),
event.getColor(),
Colors.legibleTextColor(event.getColor()),
startTime,
endTime,
event.startTime == null,
event.id, !event.seen));
if (!event.seen) {
unreadEventDates.add(event.eventDate.getValue());
}
}
/*List<LessonFull> lessonChanges = app.db.lessonChangeDao().getAllChangesWithLessonsNow(App.profileId);
for (LessonFull lesson: lessonChanges) {
Calendar startTime = Calendar.getInstance();
Calendar endTime = Calendar.getInstance();
if (lesson.lessonDate == null) {
continue;
}
startTime.set(lesson.lessonDate.year, lesson.lessonDate.month - 1, lesson.lessonDate.day, lesson.startTime.hour, lesson.startTime.minute, lesson.startTime.second);
endTime.setTimeInMillis(startTime.getTimeInMillis() + (1000 * 60 * 45));
String description = lesson.changeTypeStr(activity);
if (lesson.changeType != TYPE_CANCELLED) {
if (lesson.subjectId != lesson.changeSubjectId && lesson.teacherId != lesson.changeTeacherId) {
description += " -> " + bs(null, lesson.changeSubjectLongName, ", ") + bs(lesson.changeTeacherFullName);
} else if (lesson.subjectId != lesson.changeSubjectId) {
description += " -> " + bs(lesson.changeSubjectLongName);
} else if (lesson.teacherId != lesson.changeTeacherId) {
description += " -> " + bs(lesson.changeTeacherFullName);
}
}
eventList.add(new BaseCalendarEvent(description,
"",
(lesson.startTime.getStringHM()) +
Utils.bs(", ", lesson.subjectLongName) +
Utils.bs(", ", lesson.teacherFullName) +
Utils.bs(", ", lesson.teamName),
0xff78909c,
Colors.legibleTextColor(0xff78909c),
startTime,
endTime,
false,
(int)lesson.changeId, false));
}*/
activity.runOnUiThread(() -> {
AgendaCalendarView mAgendaCalendarView = b_default.agendaDefaultView;
// minimum and maximum date of our calendar
// 2 month behind, one year ahead, example: March 2015 <-> May 2015 <-> May 2016
Calendar minDate = Calendar.getInstance();
Calendar maxDate = Calendar.getInstance();
minDate.add(Calendar.MONTH, -2);
minDate.set(Calendar.DAY_OF_MONTH, 1);
maxDate.add(Calendar.MONTH, 2);
mAgendaCalendarView.init(eventList, minDate, maxDate, Locale.getDefault(), new CalendarPickerController() {
@Override
public void onDaySelected(IDayItem dayItem) {
}
@Override
public void onScrollToDate(Calendar calendar) {
actualDate = Date.fromCalendar(calendar);
int scrolledDate = actualDate.getValue();
if (unreadEventDates.contains(scrolledDate)) {
AsyncTask.execute(() -> App.db.eventDao().setSeenByDate(App.Companion.getProfileId(), Date.fromYmd(intToStr(scrolledDate)), true));
unreadEventDates.remove((Integer) scrolledDate);
}
}
@Override
public void onEventSelected(CalendarEvent calendarEvent) {
if (calendarEvent instanceof BaseCalendarEvent) {
/*if (!calendarEvent.isPlaceholder() && !calendarEvent.isAllDay()) {
// new EventListDialogOld(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()), Time.fromMillis(calendarEvent.getStartTime().getTimeInMillis()), true);
new EventListDialog(
activity,
App.profileId,
Date.fromCalendar(calendarEvent.getInstanceDay()),
Time.fromMillis(calendarEvent.getStartTime().getTimeInMillis()),
null,
null);
} else {*/
// new EventListDialogOld(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
new DayDialog(
activity,
App.Companion.getProfileId(),
Date.fromCalendar(calendarEvent.getInstanceDay()),
null,
null
);
/*new EventListDialog(
activity,
App.profileId,
Date.fromCalendar(calendarEvent.getInstanceDay()),
null,
null,
null);*/
//}
} else if (calendarEvent instanceof LessonChangeEvent) {
new LessonChangeDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
//Toast.makeText(app, "Clicked "+((LessonChangeEvent) calendarEvent).getLessonChangeDate().getFormattedString(), Toast.LENGTH_SHORT).show();
} else if (calendarEvent instanceof TeacherAbsenceEvent) {
new TeacherAbsenceDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
}
}
}, new LessonChangeEventRenderer(), new TeacherAbsenceEventRenderer());
b_default.progressBar.setVisibility(View.GONE);
});
}), 500);
}
private void createCalendarAgendaView() {
List<Integer> unreadEventDates = new ArrayList<>();
final Handler handler = new Handler();
handler.postDelayed(() -> AsyncTask.execute(() -> {
if (app == null || activity == null || b_calendar == null || !isAdded())
return;
Context c = getContext();
Activity a = getActivity();
assert c != null;
assert a != null;
if (!isAdded()) {
return;
}
List<EventDay> eventList = new ArrayList<>();
List<EventFull> events = App.db.eventDao().getAllNow(App.Companion.getProfileId());
for (EventFull event : events) {
if (event.eventDate == null)
continue;
Calendar startTime = Calendar.getInstance();
startTime.set(
event.eventDate.year,
event.eventDate.month - 1,
event.eventDate.day,
event.startTime == null ? 0 : event.startTime.hour,
event.startTime == null ? 0 : event.startTime.minute,
event.startTime == null ? 0 : event.startTime.second
);
Drawable eventIcon = new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_checkbox_blank_circle).size(IconicsSize.dp(10)).color(IconicsColor.colorInt(event.getColor()));
eventList.add(new EventDay(startTime, eventIcon));
if (!event.seen) {
unreadEventDates.add(event.eventDate.getValue());
}
}
/* List<LessonFull> lessonChanges = app.db.lessonChangeDao().getAllChangesWithLessonsNow(App.profileId);
for (LessonFull lesson: lessonChanges) {
Calendar startTime = Calendar.getInstance();
if (lesson.lessonDate == null) {
continue;
}
startTime.set(
lesson.lessonDate.year,
lesson.lessonDate.month - 1,
lesson.lessonDate.day,
lesson.startTime.hour,
lesson.startTime.minute,
lesson.startTime.second);
Drawable eventIcon = new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_checkbox_blank_circle).size(IconicsSize.dp(10)).color(IconicsColor.colorInt(0xff78909c));
eventList.add(new EventDay(startTime, eventIcon));
} TODO: Implement new timetable lesson changes */
getActivity().runOnUiThread(() -> {
//List<EventDay> eventList = new ArrayList<>();
//Collections.sort(eventList, new EventListComparator());
CalendarView calendarView = b_calendar.agendaCalendarView;
calendarView.setEvents(eventList);
calendarView.setOnDayClickListener(eventDay -> {
Date dayDate = Date.fromCalendar(eventDay.getCalendar());
int scrolledDate = dayDate.getValue();
if (unreadEventDates.contains(scrolledDate)) {
AsyncTask.execute(() -> App.db.eventDao().setSeenByDate(App.Companion.getProfileId(), Date.fromYmd(intToStr(scrolledDate)), true));
unreadEventDates.remove((Integer) scrolledDate);
}
new DayDialog(
activity,
App.Companion.getProfileId(),
dayDate,
null,
null
);
// new EventListDialogOld(getContext()).show(app, dayDate);
/*new EventListDialog(
activity,
App.profileId,
dayDate,
null,
null,
null
);*/
});
b_calendar.progressBar.setVisibility(View.GONE);
});
}), 300);
}
public static class EventListComparator implements java.util.Comparator<CalendarEvent> {
@Override
public int compare(CalendarEvent o1, CalendarEvent o2) {
return Long.compare(o1.getStartTime().getTimeInMillis(), o2.getStartTime().getTimeInMillis());
//return (int)(o1.getStartTime().getTimeInMillis() - o2.getStartTime().getTimeInMillis());
}
}
}

View File

@ -0,0 +1,296 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-25
*/
package pl.szczodrzynski.edziennik.ui.modules.agenda
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import com.applandeo.materialcalendarview.EventDay
import com.github.tibolte.agendacalendarview.CalendarPickerController
import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent
import com.github.tibolte.agendacalendarview.models.CalendarEvent
import com.github.tibolte.agendacalendarview.models.IDayItem
import com.mikepenz.iconics.IconicsColor
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.IconicsSize
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial.Icon2
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding
import pl.szczodrzynski.edziennik.ui.dialogs.day.DayDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.dialogs.teacherabsence.TeacherAbsenceDialog
import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeCounter
import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEvent
import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEventRenderer
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceCounter
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEvent
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEventRenderer
import pl.szczodrzynski.edziennik.utils.Colors
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import java.util.*
import kotlin.coroutines.CoroutineContext
class AgendaFragment : Fragment(), CoroutineScope {
private lateinit var activity: MainActivity
private lateinit var b: ViewDataBinding
private val app by lazy { activity.app }
private var job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private var type: Int = Profile.AGENDA_DEFAULT
private var actualDate: Date? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (getActivity() == null || context == null) return null
activity = getActivity() as MainActivity
context?.theme?.applyStyle(Themes.appTheme, true)
type = app.config.forProfile().ui.agendaViewType
b = when (type) {
Profile.AGENDA_DEFAULT -> FragmentAgendaDefaultBinding.inflate(inflater, container, false)
Profile.AGENDA_CALENDAR -> FragmentAgendaCalendarBinding.inflate(inflater, container, false)
else -> return null
}
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded) return
activity.bottomSheet.prependItems(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_add_event)
.withDescription(R.string.menu_add_event_desc)
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
EventManualDialog(activity, app.profileId, defaultDate = actualDate)
}),
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_agenda_change_view)
.withIcon(if (type == Profile.AGENDA_DEFAULT) CommunityMaterial.Icon.cmd_calendar_outline else CommunityMaterial.Icon.cmd_format_list_bulleted_square)
.withOnClickListener(View.OnClickListener {
activity.bottomSheet.close()
type = if (type == Profile.AGENDA_DEFAULT) Profile.AGENDA_CALENDAR else Profile.AGENDA_DEFAULT
app.config.forProfile().ui.agendaViewType = type
activity.reloadTarget()
}),
BottomSheetSeparatorItem(true),
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_mark_as_read)
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
.withOnClickListener(View.OnClickListener { launch {
activity.bottomSheet.close()
withContext(Dispatchers.Default) {
App.db.metadataDao().setAllSeen(app.profileId, Metadata.TYPE_EVENT, true)
}
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
}})
)
activity.navView.bottomBar.fabEnable = true
activity.navView.bottomBar.fabExtendedText = getString(R.string.add)
activity.navView.bottomBar.fabIcon = Icon2.cmd_plus
activity.navView.setFabOnClickListener(View.OnClickListener {
EventManualDialog(activity, app.profileId, defaultDate = actualDate)
})
activity.gainAttention()
activity.gainAttentionFAB()
when (type) {
Profile.AGENDA_DEFAULT -> createDefaultAgendaView()
Profile.AGENDA_CALENDAR -> createCalendarAgendaView()
}
}
private fun createDefaultAgendaView() { (b as? FragmentAgendaDefaultBinding)?.let { b -> launch {
delay(500)
val eventList = mutableListOf<CalendarEvent>()
val minDate = Calendar.getInstance().apply {
add(Calendar.MONTH, -2)
set(Calendar.DAY_OF_MONTH, 1)
}
val maxDate = Calendar.getInstance().apply { add(Calendar.MONTH, 2) }
/**
* LESSON CHANGES
*/
val lessons = withContext(Dispatchers.Default) { app.db.timetableDao().getAllChangesNow(app.profileId) }
val lessonChangeCounters = mutableListOf<LessonChangeCounter>()
lessons.forEach { lesson ->
lessonChangeCounters.firstOrNull { it.lessonChangeDate == lesson.displayDate }?.let {
it.lessonChangeCount += 1
} ?: run {
lessonChangeCounters.add(LessonChangeCounter(
lesson.displayDate ?: return@forEach,
1
))
}
}
lessonChangeCounters.forEach { counter ->
eventList.add(LessonChangeEvent(
counter.lessonChangeDate.inMillis,
0xff78909c.toInt(),
Colors.legibleTextColor(0xff78909c.toInt()),
counter.startTime,
counter.endTime,
app.profileId,
counter.lessonChangeDate,
counter.lessonChangeCount
))
}
/**
* TEACHER ABSENCES
*/
val showTeacherAbsences = app.profile.getStudentData("showTeacherAbsences", true)
if (showTeacherAbsences) {
val teacherAbsenceList = withContext(Dispatchers.Default) { app.db.teacherAbsenceDao().getAllFullNow(app.profileId) }
val teacherAbsenceCounters = mutableListOf<TeacherAbsenceCounter>()
teacherAbsenceList.forEach { absence ->
val date = absence.dateFrom.clone()
while (date <= absence.dateTo) {
teacherAbsenceCounters.firstOrNull { it.teacherAbsenceDate == date }?.let {
it.teacherAbsenceCount += 1
} ?: run {
teacherAbsenceCounters.add(TeacherAbsenceCounter(date.clone(), 1))
}
date.stepForward(0, 0, 1)
}
}
teacherAbsenceCounters.forEach { counter ->
eventList.add(TeacherAbsenceEvent(
counter.teacherAbsenceDate.inMillis,
0xffff1744.toInt(),
Colors.legibleTextColor(0xffff1744.toInt()),
counter.startTime,
counter.endTime,
app.profileId,
counter.teacherAbsenceDate,
counter.teacherAbsenceCount
))
}
}
/**
* EVENTS
*/
val events = withContext(Dispatchers.Default) { app.db.eventDao().getAllNow(app.profileId) }
val unreadEventDates = mutableSetOf<Int>()
events.forEach { event ->
eventList.add(BaseCalendarEvent(
"${event.typeName} - ${event.topic}",
"",
if (event.startTime == null) getString(R.string.agenda_event_all_day) else event.startTime!!.stringHM +
(event.subjectLongName?.let { ", $it" } ?: "") +
(event.teacherFullName?.let { ", $it" } ?: "") +
(event.teamName?.let { ", $it" } ?: ""),
event.getColor(),
Colors.legibleTextColor(event.getColor()),
event.startTimeCalendar,
event.endTimeCalendar,
event.startTime == null,
event.id,
!event.seen
))
if (!event.seen) unreadEventDates.add(event.eventDate.value)
}
b.agendaDefaultView.init(eventList, minDate, maxDate, Locale.getDefault(), object : CalendarPickerController {
override fun onDaySelected(dayItem: IDayItem?) {}
override fun onScrollToDate(calendar: Calendar) { this@AgendaFragment.launch {
val date = Date.fromCalendar(calendar)
actualDate = date
// Mark as read scrolled date
if (date.value in unreadEventDates) {
withContext(Dispatchers.Default) { app.db.eventDao().setSeenByDate(app.profileId, date, true) }
unreadEventDates.remove(date.value)
}
}}
override fun onEventSelected(event: CalendarEvent) {
val date = Date.fromCalendar(event.instanceDay)
when (event) {
is BaseCalendarEvent -> DayDialog(activity, app.profileId, date)
// is LessonChangeEvent -> todo
is TeacherAbsenceEvent -> TeacherAbsenceDialog(activity, app.profileId, date)
}
}
}, LessonChangeEventRenderer(), TeacherAbsenceEventRenderer())
b.progressBar.visibility = View.GONE
}}}
private fun createCalendarAgendaView() { (b as? FragmentAgendaCalendarBinding)?.let { b -> launch {
delay(300)
val dayList = mutableListOf<EventDay>()
val events = withContext(Dispatchers.Default) { app.db.eventDao().getAllNow(app.profileId) }
val unreadEventDates = mutableSetOf<Int>()
events.forEach { event ->
val eventIcon = IconicsDrawable(activity)
.icon(CommunityMaterial.Icon.cmd_checkbox_blank_circle)
.size(IconicsSize.dp(10))
.color(IconicsColor.colorInt(event.getColor()))
dayList.add(EventDay(event.startTimeCalendar, eventIcon))
if (!event.seen) unreadEventDates.add(event.eventDate.value)
}
b.agendaCalendarView.setEvents(dayList)
b.agendaCalendarView.setOnDayClickListener { day -> this@AgendaFragment.launch {
val date = Date.fromCalendar(day.calendar)
if (date.value in unreadEventDates) {
withContext(Dispatchers.Default) { app.db.eventDao().setSeenByDate(app.profileId, date, true) }
unreadEventDates.remove(date.value)
}
DayDialog(activity, app.profileId, date)
}}
b.progressBar.visibility = View.GONE
}}}
}

View File

@ -1,9 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange;
import pl.szczodrzynski.edziennik.utils.models.Date;
public class LessonChangeCounter {
public int profileId;
public Date lessonChangeDate;
public int lessonChangeCount;
}

View File

@ -0,0 +1,19 @@
package pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange
import pl.szczodrzynski.edziennik.utils.models.Date
import java.util.*
class LessonChangeCounter(
val lessonChangeDate: Date,
var lessonChangeCount: Int
) {
val startTime: Calendar
get() = Calendar.getInstance().apply {
set(lessonChangeDate.year, lessonChangeDate.month - 1, lessonChangeDate.day, 10, 0, 0)
}
val endTime: Calendar
get() = Calendar.getInstance().apply {
timeInMillis = startTime.timeInMillis + (45 * 60 * 1000)
}
}

View File

@ -1,28 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange;
import android.view.View;
import android.widget.TextView;
import androidx.cardview.widget.CardView;
import com.github.tibolte.agendacalendarview.render.EventRenderer;
import pl.szczodrzynski.edziennik.R;
public class LessonChangeEventRenderer extends EventRenderer<LessonChangeEvent> {
@Override
public void render(View view, LessonChangeEvent event) {
CardView card = view.findViewById(R.id.lesson_change_card);
TextView changeText = view.findViewById(R.id.lesson_change_text);
TextView changeCount = view.findViewById(R.id.lessonChangeCount);
card.setCardBackgroundColor(event.getColor());
changeText.setTextColor(event.getTextColor());
changeCount.setTextColor(event.getTextColor());
changeCount.setText(String.valueOf(event.getLessonChangeCount()));
}
@Override
public int getEventLayout() {
return R.layout.agenda_event_lesson_change;
}
}

View File

@ -0,0 +1,21 @@
package pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange
import android.view.View
import android.widget.TextView
import androidx.cardview.widget.CardView
import com.github.tibolte.agendacalendarview.render.EventRenderer
import pl.szczodrzynski.edziennik.R
class LessonChangeEventRenderer : EventRenderer<LessonChangeEvent>() {
override fun render(view: View?, event: LessonChangeEvent) {
val card = view?.findViewById<CardView>(R.id.lesson_change_card)
val changeText = view?.findViewById<TextView>(R.id.lesson_change_text)
val changeCount = view?.findViewById<TextView>(R.id.lessonChangeCount)
card?.setCardBackgroundColor(event.color)
changeText?.setTextColor(event.textColor)
changeCount?.setTextColor(event.textColor)
changeCount?.text = event.lessonChangeCount.toString()
}
override fun getEventLayout(): Int = R.layout.agenda_event_lesson_change
}

View File

@ -1,10 +1,19 @@
package pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence
import pl.szczodrzynski.edziennik.utils.models.Date
import java.util.*
class TeacherAbsenceCounter (
val teacherAbsenceDate: Date,
var teacherAbsenceCount: Int = 0
)
) {
val startTime: Calendar
get() = Calendar.getInstance().apply {
set(teacherAbsenceDate.year, teacherAbsenceDate.month - 1, teacherAbsenceDate.day, 10, 0, 0)
}
val endTime: Calendar
get() = Calendar.getInstance().apply {
timeInMillis = startTime.timeInMillis + (45 * 60 * 1000)
}
}

View File

@ -17,5 +17,5 @@ class TeacherAbsenceEventRenderer : EventRenderer<TeacherAbsenceEvent>() {
changeCount?.text = event.teacherAbsenceCount.toString()
}
override fun getEventLayout(): Int { return R.layout.agenda_event_teacher_absence }
override fun getEventLayout(): Int = R.layout.agenda_event_teacher_absence
}

View File

@ -37,8 +37,6 @@ class HomeworkFragment : Fragment() {
return null
app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true)
if (app.profile == null)
return inflater.inflate(R.layout.fragment_loading, container, false)
// activity, context and profile is valid
b = FragmentHomeworkBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout)