mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-25 11:35:30 +02:00
[Structure] Move fragments, activities and adapters to specific modules
This commit is contained in:
@ -0,0 +1,243 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.agenda;
|
||||
|
||||
import com.github.tibolte.agendacalendarview.models.CalendarEvent;
|
||||
import com.github.tibolte.agendacalendarview.models.IDayItem;
|
||||
import com.github.tibolte.agendacalendarview.models.IWeekItem;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
|
||||
public class LessonChangeEvent implements CalendarEvent {
|
||||
|
||||
/**
|
||||
* Id of the event.
|
||||
*/
|
||||
private long mId;
|
||||
/**
|
||||
* Color to be displayed in the agenda view.
|
||||
*/
|
||||
private int mColor;
|
||||
/**
|
||||
* Text color displayed on the background color
|
||||
*/
|
||||
private int mTextColor;
|
||||
/**
|
||||
* Calendar instance helping sorting the events per section in the agenda view.
|
||||
*/
|
||||
private Calendar mInstanceDay;
|
||||
/**
|
||||
* Start time of the event.
|
||||
*/
|
||||
private Calendar mStartTime;
|
||||
/**
|
||||
* End time of the event.
|
||||
*/
|
||||
private Calendar mEndTime;
|
||||
/**
|
||||
* References to a DayItem instance for that event, used to link interaction between the
|
||||
* calendar view and the agenda view.
|
||||
*/
|
||||
private IDayItem mDayReference;
|
||||
/**
|
||||
* References to a WeekItem instance for that event, used to link interaction between the
|
||||
* calendar view and the agenda view.
|
||||
*/
|
||||
private IWeekItem mWeekReference;
|
||||
|
||||
|
||||
private int profileId;
|
||||
private Date lessonChangeDate;
|
||||
private int lessonChangeCount;
|
||||
|
||||
public LessonChangeEvent(LessonChangeEvent calendarEvent) {
|
||||
this.mId = calendarEvent.getId();
|
||||
this.mColor = calendarEvent.getColor();
|
||||
this.mTextColor = calendarEvent.getTextColor();
|
||||
this.mStartTime = calendarEvent.getStartTime();
|
||||
this.mEndTime = calendarEvent.getEndTime();
|
||||
this.profileId = calendarEvent.getProfileId();
|
||||
this.lessonChangeDate = calendarEvent.getLessonChangeDate();
|
||||
this.lessonChangeCount = calendarEvent.getLessonChangeCount();
|
||||
}
|
||||
|
||||
public LessonChangeEvent(long mId, int mColor, int mTextColor, Calendar mStartTime, Calendar mEndTime, int profileId, Date lessonChangeDate, int lessonChangeCount) {
|
||||
this.mId = mId;
|
||||
this.mColor = mColor;
|
||||
this.mTextColor = mTextColor;
|
||||
this.mStartTime = mStartTime;
|
||||
this.mEndTime = mEndTime;
|
||||
this.profileId = profileId;
|
||||
this.lessonChangeDate = lessonChangeDate;
|
||||
this.lessonChangeCount = lessonChangeCount;
|
||||
}
|
||||
|
||||
public int getProfileId() {
|
||||
return profileId;
|
||||
}
|
||||
|
||||
public Date getLessonChangeDate() {
|
||||
return lessonChangeDate;
|
||||
}
|
||||
|
||||
public int getLessonChangeCount() {
|
||||
return lessonChangeCount;
|
||||
}
|
||||
|
||||
public void setProfileId(int profileId) {
|
||||
this.profileId = profileId;
|
||||
}
|
||||
|
||||
public void setLessonChangeDate(Date lessonChangeDate) {
|
||||
this.lessonChangeDate = lessonChangeDate;
|
||||
}
|
||||
|
||||
public void setLessonChangeCount(int lessonChangeCount) {
|
||||
this.lessonChangeCount = lessonChangeCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaceholder(boolean placeholder) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlaceholder() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocation(String mLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(long mId) {
|
||||
this.mId = mId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getShowBadge() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowBadge(boolean mShowBadge) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTextColor() {
|
||||
return mTextColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(int mTextColor) {
|
||||
this.mTextColor = mTextColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String mDescription) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllDay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllDay(boolean allDay) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getStartTime() {
|
||||
return mStartTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartTime(Calendar mStartTime) {
|
||||
this.mStartTime = mStartTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getEndTime() {
|
||||
return mEndTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEndTime(Calendar mEndTime) {
|
||||
this.mEndTime = mEndTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String mTitle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getInstanceDay() {
|
||||
return mInstanceDay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInstanceDay(Calendar mInstanceDay) {
|
||||
this.mInstanceDay = mInstanceDay;
|
||||
this.mInstanceDay.set(Calendar.HOUR, 0);
|
||||
this.mInstanceDay.set(Calendar.MINUTE, 0);
|
||||
this.mInstanceDay.set(Calendar.SECOND, 0);
|
||||
this.mInstanceDay.set(Calendar.MILLISECOND, 0);
|
||||
this.mInstanceDay.set(Calendar.AM_PM, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDayItem getDayReference() {
|
||||
return mDayReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDayReference(IDayItem mDayReference) {
|
||||
this.mDayReference = mDayReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWeekItem getWeekReference() {
|
||||
return mWeekReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWeekReference(IWeekItem mWeekReference) {
|
||||
this.mWeekReference = mWeekReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarEvent copy() {
|
||||
return new LessonChangeEvent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor() {
|
||||
return mColor;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.agenda;
|
||||
|
||||
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.lesson_change_count);
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
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 androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.applandeo.materialcalendarview.CalendarView;
|
||||
import com.applandeo.materialcalendarview.EventDay;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterAgendaCalendarBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.intToStr;
|
||||
|
||||
public class RegisterAgendaCalendarFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private Activity activity = null;
|
||||
private FragmentRegisterAgendaCalendarBinding b = null;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = getActivity();
|
||||
if (getActivity() == null || getContext() == null)
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_agenda_calendar, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
List<Integer> unreadEventDates = new ArrayList<>();
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(() -> AsyncTask.execute(() -> {
|
||||
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.profileId);
|
||||
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));
|
||||
}
|
||||
|
||||
getActivity().runOnUiThread(() -> {
|
||||
//List<EventDay> eventList = new ArrayList<>();
|
||||
|
||||
//Collections.sort(eventList, new EventListComparator());
|
||||
|
||||
CalendarView calendarView = b.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.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove(unreadEventDates.indexOf(scrolledDate));
|
||||
}
|
||||
|
||||
new EventListDialog(getContext()).show(app, dayDate);
|
||||
});
|
||||
b.progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
}), 300);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,365 @@
|
||||
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 androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterAgendaCalendarBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterAgendaDefaultBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.lessonchange.LessonChangeDialog;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.db.LessonChangeCounter;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Metadata.TYPE_EVENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.AGENDA_CALENDAR;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.AGENDA_DEFAULT;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.intToStr;
|
||||
|
||||
public class RegisterAgendaDefaultFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterAgendaDefaultBinding b_default = null;
|
||||
private FragmentRegisterAgendaCalendarBinding b_calendar = null;
|
||||
private int viewType = AGENDA_DEFAULT;
|
||||
|
||||
@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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
viewType = app.profile.getAgendaViewType();
|
||||
if (viewType == AGENDA_DEFAULT) {
|
||||
b_default = DataBindingUtil.inflate(inflater, R.layout.fragment_register_agenda_default, container, false);
|
||||
return b_default.getRoot();
|
||||
}
|
||||
else {
|
||||
b_calendar = DataBindingUtil.inflate(inflater, R.layout.fragment_register_agenda_calendar, container, false);
|
||||
return b_calendar.getRoot();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == 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(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.main_menu_add)
|
||||
.items(R.array.main_menu_add_options)
|
||||
.itemsCallback((dialog, itemView, position, text) -> {
|
||||
switch (position) {
|
||||
case 0:
|
||||
new EventManualDialog(activity).show(app, null, null, null, EventManualDialog.DIALOG_EVENT);
|
||||
break;
|
||||
case 1:
|
||||
new EventManualDialog(activity).show(app, null, null, null, EventManualDialog.DIALOG_HOMEWORK);
|
||||
break;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_agenda_change_view)
|
||||
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar : CommunityMaterial.Icon2.cmd_view_list)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
|
||||
app.profile.setAgendaViewType(viewType);
|
||||
app.profileSaveAsync();
|
||||
activity.reloadTarget();
|
||||
}),
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_EVENT, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
activity.gainAttention();
|
||||
|
||||
if (viewType == AGENDA_DEFAULT) {
|
||||
List<Integer> unreadEventDates = new ArrayList<>();
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(() -> AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == 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
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
List<EventFull> events = app.db.eventDao().getAllNow(App.profileId);
|
||||
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) {
|
||||
int scrolledDate = Date.fromCalendar(calendar).getValue();
|
||||
if (unreadEventDates.contains(scrolledDate)) {
|
||||
AsyncTask.execute(() -> app.db.eventDao().setSeenByDate(App.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove(unreadEventDates.indexOf(scrolledDate));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEventSelected(CalendarEvent calendarEvent) {
|
||||
if (calendarEvent instanceof BaseCalendarEvent) {
|
||||
if (!calendarEvent.isPlaceholder() && !calendarEvent.isAllDay()) {
|
||||
new EventListDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()), Time.fromMillis(calendarEvent.getStartTime().getTimeInMillis()), true);
|
||||
} else {
|
||||
new EventListDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}, new LessonChangeEventRenderer());
|
||||
b_default.progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
}), 500);
|
||||
}
|
||||
else {
|
||||
List<Integer> unreadEventDates = new ArrayList<>();
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(() -> AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == 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.profileId);
|
||||
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));
|
||||
}
|
||||
|
||||
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.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove(unreadEventDates.indexOf(scrolledDate));
|
||||
}
|
||||
|
||||
new EventListDialog(getContext()).show(app, dayDate);
|
||||
});
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.announcements;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.RowAnnouncementsItemBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.AnnouncementFull;
|
||||
|
||||
public class AnnouncementsAdapter extends RecyclerView.Adapter<AnnouncementsAdapter.ViewHolder> {
|
||||
|
||||
private Context context;
|
||||
public List<AnnouncementFull> announcementList;
|
||||
public OnAnnouncementClickListener onClick;
|
||||
|
||||
public interface OnAnnouncementClickListener {
|
||||
void onClick(View v, AnnouncementFull announcement);
|
||||
}
|
||||
|
||||
public AnnouncementsAdapter(Context context, List<AnnouncementFull> announcementList, OnAnnouncementClickListener onClick) {
|
||||
//setHasStableIds(true);
|
||||
|
||||
this.context = context;
|
||||
this.announcementList = announcementList;
|
||||
this.onClick = onClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return announcementList.size();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.row_announcements_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int groupPosition) {
|
||||
AnnouncementFull item = announcementList.get(groupPosition);
|
||||
RowAnnouncementsItemBinding b = holder.b;
|
||||
|
||||
b.announcementsItemCard.setOnClickListener((v -> {
|
||||
if (onClick != null) {
|
||||
onClick.onClick(v, item);
|
||||
}
|
||||
}));
|
||||
b.announcementsItemSender.setText(item.teacherFullName);
|
||||
b.announcementsItemTitle.setText(item.subject);
|
||||
b.announcementsItemText.setText(item.text);
|
||||
b.announcementsItemDate.setText(item.startDate.getFormattedString()+(item.endDate == null ? "" : " - "+item.endDate.getFormattedString()));
|
||||
if (!item.seen) {
|
||||
b.announcementsItemTitle.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
|
||||
b.announcementsItemTitle.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
b.announcementsItemSender.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
b.announcementsItemTitle.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
} else {
|
||||
b.announcementsItemSender.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
|
||||
b.announcementsItemTitle.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
|
||||
b.announcementsItemTitle.setBackground(null);
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
RowAnnouncementsItemBinding b;
|
||||
|
||||
ViewHolder(RowAnnouncementsItemBinding b) {
|
||||
super(b.getRoot());
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.announcements;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogAnnouncementBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterSchoolNoticesBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Metadata.TYPE_ANNOUNCEMENT;
|
||||
|
||||
public class RegisterAnnouncementsFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterSchoolNoticesBinding b = 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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_school_notices, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ANNOUNCEMENT, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_ANNOUNCEMENTS, b.refreshLayout);
|
||||
});*/
|
||||
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
|
||||
//RecyclerViewExpandableItemManager expMgr = new RecyclerViewExpandableItemManager(null);
|
||||
|
||||
recyclerView = b.announcementsView;
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(linearLayoutManager);
|
||||
|
||||
|
||||
|
||||
|
||||
app.db.announcementDao().getAll(App.profileId).observe(this, announcements -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (announcements == null) {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
b.announcementsNoData.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (announcements.size() > 0) {
|
||||
/*if ((adapter = (AnnouncementsAdapter) recyclerView.getAdapter()) != null) {
|
||||
adapter.announcementList = announcements;
|
||||
adapter.notifyDataSetChanged();
|
||||
return;
|
||||
}*/
|
||||
AnnouncementsAdapter announcementsAdapter = new AnnouncementsAdapter(activity, announcements, (v, announcement) -> {
|
||||
MaterialDialog dialog = new MaterialDialog.Builder(activity)
|
||||
.title(announcement.subject)
|
||||
.customView(R.layout.dialog_announcement, true)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
DialogAnnouncementBinding b = DialogAnnouncementBinding.bind(dialog.getCustomView());
|
||||
b.text.setText(announcement.teacherFullName+"\n\n"+ (announcement.startDate != null ? announcement.startDate.getFormattedString() : "-")+" do "+ (announcement.endDate != null ? announcement.endDate.getFormattedString() : "-")+"\n\n" +announcement.text);
|
||||
if (!announcement.seen) {
|
||||
announcement.seen = true;
|
||||
AsyncTask.execute(() -> {
|
||||
app.db.metadataDao().setSeen(App.profileId, announcement, true);
|
||||
});
|
||||
if (recyclerView.getAdapter() != null)
|
||||
recyclerView.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
|
||||
recyclerView.setAdapter(announcementsAdapter);
|
||||
// NOTE: need to disable change animations to ripple effect work properly
|
||||
//((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
|
||||
//expMgr.attachRecyclerView(recyclerView);
|
||||
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
b.announcementsNoData.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
b.announcementsNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.attendance;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.os.AsyncTask;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.datamodels.AttendanceFull;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_ABSENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_ABSENT_EXCUSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_BELATED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_BELATED_EXCUSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_PRESENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_RELEASED;
|
||||
|
||||
public class AttendancesAdapter extends RecyclerView.Adapter<AttendancesAdapter.ViewHolder> {
|
||||
private Context context;
|
||||
public List<AttendanceFull> attendanceList;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public AttendancesAdapter(Context mCtx, List<AttendanceFull> noticeList) {
|
||||
this.context = mCtx;
|
||||
this.attendanceList = noticeList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.row_attendance_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
|
||||
AttendanceFull attendance = attendanceList.get(position);
|
||||
|
||||
holder.attendanceLessonTopic.setText(attendance.lessonTopic);
|
||||
holder.attendanceTeacher.setText(attendance.teacherFullName);
|
||||
holder.attendanceSubject.setText(attendance.subjectLongName);
|
||||
holder.attendanceDate.setText(attendance.lessonDate.getStringDmy());
|
||||
holder.attendanceTime.setText(attendance.startTime.getStringHM());
|
||||
|
||||
switch (attendance.type) {
|
||||
case TYPE_ABSENT:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xfff44336, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText(R.string.attendance_absent);
|
||||
break;
|
||||
case TYPE_ABSENT_EXCUSED:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xffaeea00, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText(R.string.attendance_absent_excused);
|
||||
break;
|
||||
case TYPE_BELATED:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xffffca28, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText(R.string.attendance_belated);
|
||||
break;
|
||||
case TYPE_BELATED_EXCUSED:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xff4bb733, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText(R.string.attendance_belated_excused);
|
||||
break;
|
||||
case TYPE_RELEASED:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xff9e9e9e, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText(R.string.attendance_released);
|
||||
break;
|
||||
case TYPE_PRESENT:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xffffae00, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText(R.string.attendance_present);
|
||||
break;
|
||||
default:
|
||||
holder.attendanceType.getBackground().setColorFilter(new PorterDuffColorFilter(0xff03a9f4, PorterDuff.Mode.MULTIPLY));
|
||||
holder.attendanceType.setText("?");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!attendance.seen) {
|
||||
holder.attendanceLessonTopic.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
|
||||
holder.attendanceLessonTopic.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
attendance.seen = true;
|
||||
AsyncTask.execute(() -> {
|
||||
app.db.metadataDao().setSeen(App.profileId, attendance, true);
|
||||
//Intent i = new Intent("android.intent.action.MAIN").putExtra(MainActivity.ACTION_UPDATE_BADGES, "yes, sure");
|
||||
//context.sendBroadcast(i);
|
||||
});
|
||||
}
|
||||
else {
|
||||
holder.attendanceLessonTopic.setBackground(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return attendanceList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView attendanceType;
|
||||
TextView attendanceLessonTopic;
|
||||
TextView attendanceSubject;
|
||||
TextView attendanceTeacher;
|
||||
TextView attendanceDate;
|
||||
TextView attendanceTime;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
attendanceType = itemView.findViewById(R.id.attendanceType);
|
||||
attendanceLessonTopic = itemView.findViewById(R.id.attendanceLessonTopic);
|
||||
attendanceSubject = itemView.findViewById(R.id.attendanceSubject);
|
||||
attendanceTeacher = itemView.findViewById(R.id.attendanceTeacher);
|
||||
attendanceDate = itemView.findViewById(R.id.attendanceDate);
|
||||
attendanceTime = itemView.findViewById(R.id.attendanceTime);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,363 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.attendance;
|
||||
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.LongSparseArray;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
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 java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import antonkozyriatskyi.circularprogressindicator.CircularProgressIndicator;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterAttendancesBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.AttendanceFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Subject;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_ABSENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_ABSENT_EXCUSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_BELATED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_BELATED_EXCUSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_PRESENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Attendance.TYPE_RELEASED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_VULCAN;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Metadata.TYPE_ATTENDANCE;
|
||||
|
||||
public class RegisterAttendancesFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterAttendancesBinding b = null;
|
||||
|
||||
private int displayMode = MODE_YEAR;
|
||||
private static final int MODE_YEAR = 0;
|
||||
private static final int MODE_SEMESTER_1 = 1;
|
||||
private static final int MODE_SEMESTER_2 = 2;
|
||||
private long subjectIdFilter = -1;
|
||||
private LongSparseArray<int[]> subjectTotalCount;
|
||||
private LongSparseArray<int[]> subjectAbsentCount;
|
||||
private LongSparseArray<Float> subjectAttendancePercentage;
|
||||
|
||||
private List<AttendanceFull> attendanceList = 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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_attendances, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ATTENDANCE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_ATTENDANCES, b.refreshLayout);
|
||||
});*/
|
||||
|
||||
b.attendancePercentage.setProgressTextAdapter(PERCENTAGE_ADAPTER);
|
||||
b.attendancePercentage.setMaxProgress(100.0f);
|
||||
|
||||
b.attendancesSummaryTitle.setOnClickListener((v -> {
|
||||
PopupMenu popupMenu = new PopupMenu(activity, b.attendancesSummaryTitle, Gravity.END);
|
||||
popupMenu.getMenu().add(0, 0, 0, R.string.summary_mode_year);
|
||||
popupMenu.getMenu().add(0, 1, 1, R.string.summary_mode_semester_1);
|
||||
popupMenu.getMenu().add(0, 2, 2, R.string.summary_mode_semester_2);
|
||||
popupMenu.setOnMenuItemClickListener((item -> {
|
||||
displayMode = item.getItemId();
|
||||
updateList();
|
||||
return true;
|
||||
}));
|
||||
popupMenu.show();
|
||||
}));
|
||||
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK) {
|
||||
long attendancesLastSync = app.profile.getStudentData("attendancesLastSync", (long)0);
|
||||
if (attendancesLastSync == 0) {
|
||||
attendancesLastSync = app.profile.getSemesterStart(1).getInMillis();
|
||||
}
|
||||
Date lastSyncDate = Date.fromMillis(attendancesLastSync);
|
||||
if (lastSyncDate.getValue() < Week.getWeekStart().getValue()) {
|
||||
CafeBar.builder(activity)
|
||||
.to(activity.getNavView().getCoordinator())
|
||||
.content(R.string.sync_old_data_info)
|
||||
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon2.cmd_sync).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
||||
.positiveText(R.string.refresh)
|
||||
.positiveColor(0xff4caf50)
|
||||
.negativeText(R.string.ok)
|
||||
.negativeColor(0x66ffffff)
|
||||
.onPositive((cafeBar -> {
|
||||
if (!activity.getSwipeRefreshLayout().isRefreshing()) {
|
||||
cafeBar.dismiss();
|
||||
activity.syncCurrentFeature();
|
||||
}
|
||||
else {
|
||||
Toast.makeText(app, R.string.please_wait, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}))
|
||||
.onNegative(CafeBar::dismiss)
|
||||
.autoDismiss(false)
|
||||
.swipeToDismiss(true)
|
||||
.floating(true)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && false) {
|
||||
b.attendancesSummarySubject.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
b.attendancesSummarySubject.setOnClickListener((v -> {
|
||||
AsyncTask.execute(() -> {
|
||||
List<Subject> subjectList = app.db.subjectDao().getAllNow(App.profileId);
|
||||
PopupMenu popupMenu = new PopupMenu(activity, b.attendancesSummarySubject, Gravity.END);
|
||||
popupMenu.getMenu().add(0, -1, 0, R.string.subject_filter_disabled);
|
||||
int index = 0;
|
||||
DecimalFormat format = new DecimalFormat("0.00");
|
||||
for (Subject subject: subjectList) {
|
||||
int total = subjectTotalCount.get(subject.id, new int[3])[displayMode];
|
||||
int absent = subjectAbsentCount.get(subject.id, new int[3])[displayMode];
|
||||
if (total == 0)
|
||||
continue;
|
||||
int present = total - absent;
|
||||
float percentage = (float)present / (float)total * 100.0f;
|
||||
String percentageStr = format.format(percentage);
|
||||
popupMenu.getMenu().add(0, (int)subject.id, index++, getString(R.string.subject_filter_format, subject.longName, percentageStr));
|
||||
}
|
||||
popupMenu.setOnMenuItemClickListener((item -> {
|
||||
subjectIdFilter = item.getItemId();
|
||||
b.attendancesSummarySubject.setText(item.getTitle().toString().replaceAll("\\s-\\s[0-9]{1,2}\\.[0-9]{1,2}%", ""));
|
||||
updateList();
|
||||
return true;
|
||||
}));
|
||||
new Handler(activity.getMainLooper()).post(popupMenu::show);
|
||||
});
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
|
||||
b.attendancesView.setHasFixedSize(true);
|
||||
b.attendancesView.setLayoutManager(linearLayoutManager);
|
||||
|
||||
app.db.attendanceDao().getAll(App.profileId).observe(this, attendances -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (attendances == null) {
|
||||
b.attendancesView.setVisibility(View.GONE);
|
||||
b.attendancesNoData.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
attendanceList = attendances;
|
||||
|
||||
countSubjectStats();
|
||||
|
||||
updateList();
|
||||
});
|
||||
}
|
||||
|
||||
private void countSubjectStats() {
|
||||
subjectTotalCount = new LongSparseArray<>();
|
||||
subjectAbsentCount = new LongSparseArray<>();
|
||||
for (AttendanceFull attendance: attendanceList) {
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_VULCAN && attendance.type == TYPE_RELEASED)
|
||||
continue;
|
||||
int[] subjectTotal = subjectTotalCount.get(attendance.subjectId, new int[3]);
|
||||
int[] subjectAbsent = subjectAbsentCount.get(attendance.subjectId, new int[3]);
|
||||
|
||||
subjectTotal[0]++;
|
||||
subjectTotal[attendance.semester]++;
|
||||
|
||||
if (attendance.type == TYPE_ABSENT || attendance.type == TYPE_ABSENT_EXCUSED) {
|
||||
subjectAbsent[0]++;
|
||||
subjectAbsent[attendance.semester]++;
|
||||
}
|
||||
|
||||
subjectTotalCount.put(attendance.subjectId, subjectTotal);
|
||||
subjectAbsentCount.put(attendance.subjectId, subjectAbsent);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
int presentCount = 0;
|
||||
int absentCount = 0;
|
||||
int absentUnexcusedCount = 0;
|
||||
int belatedCount = 0;
|
||||
int releasedCount = 0;
|
||||
|
||||
List<AttendanceFull> filteredList = new ArrayList<>();
|
||||
for (AttendanceFull attendance: attendanceList) {
|
||||
if (displayMode != MODE_YEAR && attendance.semester != displayMode)
|
||||
continue;
|
||||
if (subjectIdFilter != -1 && attendance.subjectId != subjectIdFilter)
|
||||
continue;
|
||||
if (attendance.type != TYPE_PRESENT)
|
||||
filteredList.add(attendance);
|
||||
switch (attendance.type) {
|
||||
case TYPE_PRESENT:
|
||||
presentCount++;
|
||||
break;
|
||||
case TYPE_ABSENT:
|
||||
absentCount++;
|
||||
absentUnexcusedCount++;
|
||||
break;
|
||||
case TYPE_ABSENT_EXCUSED:
|
||||
absentCount++;
|
||||
break;
|
||||
case TYPE_BELATED_EXCUSED:
|
||||
case TYPE_BELATED:
|
||||
belatedCount++;
|
||||
break;
|
||||
case TYPE_RELEASED:
|
||||
releasedCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filteredList.size() > 0) {
|
||||
AttendancesAdapter adapter;
|
||||
b.attendancesView.setVisibility(View.VISIBLE);
|
||||
b.attendancesNoData.setVisibility(View.GONE);
|
||||
if ((adapter = (AttendancesAdapter) b.attendancesView.getAdapter()) != null) {
|
||||
adapter.attendanceList = filteredList;
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
else {
|
||||
adapter = new AttendancesAdapter(getContext(), filteredList);
|
||||
b.attendancesView.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
else {
|
||||
b.attendancesView.setVisibility(View.GONE);
|
||||
b.attendancesNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// SUMMARY
|
||||
if (displayMode == MODE_YEAR) {
|
||||
b.attendancesSummaryTitle.setText(getString(R.string.attendances_summary_title_year));
|
||||
}
|
||||
else {
|
||||
b.attendancesSummaryTitle.setText(getString(R.string.attendances_summary_title_semester_format, displayMode));
|
||||
}
|
||||
b.presentCountContainer.setVisibility(presentCount == 0 ? View.GONE : View.VISIBLE);
|
||||
b.presentCount.setText(String.format(Locale.getDefault(), "%d", presentCount));
|
||||
b.absentCount.setText(String.format(Locale.getDefault(), "%d", absentCount));
|
||||
b.absentUnexcusedCount.setText(String.format(Locale.getDefault(), "%d", absentUnexcusedCount));
|
||||
b.belatedCount.setText(String.format(Locale.getDefault(), "%d", belatedCount));
|
||||
b.releasedCount.setText(String.format(Locale.getDefault(), "%d", releasedCount));
|
||||
if (absentUnexcusedCount >= 5) {
|
||||
b.absentUnexcusedCount.setTextColor(Color.RED);
|
||||
}
|
||||
else {
|
||||
b.absentUnexcusedCount.setTextColor(Themes.INSTANCE.getPrimaryTextColor(activity));
|
||||
}
|
||||
|
||||
float attendancePercentage;
|
||||
|
||||
// in Mobidziennik there are no TYPE_PRESENT records so we cannot calculate the percentage
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && false) {
|
||||
attendancePercentage = app.profile.getAttendancePercentage();
|
||||
}
|
||||
else if (app.profile.getLoginStoreType() == LOGIN_TYPE_VULCAN) {
|
||||
float allCount = presentCount + absentCount + belatedCount; // do not count releases
|
||||
float present = allCount - absentCount;
|
||||
attendancePercentage = present / allCount * 100.0f;
|
||||
}
|
||||
else {
|
||||
float allCount = presentCount + absentCount + belatedCount + releasedCount;
|
||||
float present = allCount - absentCount;
|
||||
attendancePercentage = present / allCount * 100.0f;
|
||||
}
|
||||
// if it's still 0%, hide the indicator
|
||||
if (attendancePercentage <= 0.0f) {
|
||||
b.attendancePercentage.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
animatePercentageIndicator(attendancePercentage);
|
||||
}
|
||||
|
||||
private void animatePercentageIndicator(float percentage) {
|
||||
Animation a = new Animation() {
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
float progress = percentage *interpolatedTime;
|
||||
if (interpolatedTime == 1.0f) {
|
||||
progress = percentage;
|
||||
}
|
||||
int color = ColorUtils.blendARGB(Color.RED, Color.GREEN, progress/100.0f);
|
||||
b.attendancePercentage.setTextColor(color);
|
||||
b.attendancePercentage.setProgressColor(color);
|
||||
b.attendancePercentage.setCurrentProgress(progress);
|
||||
}
|
||||
public boolean willChangeBounds() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
a.setDuration(1300);
|
||||
a.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
b.attendancePercentage.postDelayed(() -> b.attendancePercentage.startAnimation(a), 500);
|
||||
}
|
||||
|
||||
private static final CircularProgressIndicator.ProgressTextAdapter PERCENTAGE_ADAPTER = value -> {
|
||||
DecimalFormat df = new DecimalFormat("0.##");
|
||||
return df.format(value)+"%";
|
||||
};
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base;
|
||||
|
||||
/*
|
||||
* Copyright 2014-2017 Eduard Ereza Martínez
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.text.Html;
|
||||
import android.util.Base64;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import cat.ereza.customactivityoncrash.CustomActivityOnCrash;
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_ENABLED;
|
||||
|
||||
public final class CrashActivity extends AppCompatActivity {
|
||||
|
||||
private App app;
|
||||
|
||||
@SuppressLint("PrivateResource")
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.app = (App)getApplication();
|
||||
setTheme(Themes.INSTANCE.getAppTheme());
|
||||
|
||||
setContentView(R.layout.activity_crash);
|
||||
|
||||
final CaocConfig config = CustomActivityOnCrash.getConfigFromIntent(getIntent());
|
||||
|
||||
if (config == null) {
|
||||
//This should never happen - Just finish the activity to avoid a recursive crash.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
//Close/restart button logic:
|
||||
//If a class if set, use restart.
|
||||
//Else, use close and just finish the app.
|
||||
//It is recommended that you follow this logic if implementing a custom error activity.
|
||||
Button restartButton = findViewById(R.id.crash_restart_btn);
|
||||
restartButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
CustomActivityOnCrash.restartApplication(CrashActivity.this, config);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Button devMessageButton = findViewById(R.id.crash_dev_message_btn);
|
||||
devMessageButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent i = new Intent(CrashActivity.this, CrashGtfoActivity.class);
|
||||
startActivity(i);
|
||||
}
|
||||
});
|
||||
|
||||
final Button reportButton = findViewById(R.id.crash_report_btn);
|
||||
reportButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (!app.networkUtils.isOnline())
|
||||
{
|
||||
new MaterialDialog.Builder(CrashActivity.this)
|
||||
.title(R.string.network_you_are_offline_title)
|
||||
.content(R.string.network_you_are_offline_text)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
//app.networkUtils.setSelfSignedSSL(CrashActivity.this, null);
|
||||
new ServerRequest(app, app.requestScheme + APP_URL + "main.php?report", "CrashActivity")
|
||||
.setBodyParameter("base64_encoded", Base64.encodeToString(getErrorString(getIntent(), true).getBytes(), Base64.DEFAULT))
|
||||
.run((e, result) -> {
|
||||
if (result != null)
|
||||
{
|
||||
if (result.get("success").getAsBoolean()) {
|
||||
Toast.makeText(CrashActivity.this, getString(R.string.crash_report_sent), Toast.LENGTH_SHORT).show();
|
||||
reportButton.setEnabled(false);
|
||||
reportButton.setTextColor(getResources().getColor(android.R.color.darker_gray));
|
||||
}
|
||||
else {
|
||||
Toast.makeText(CrashActivity.this, getString(R.string.crash_report_cannot_send) + ": " + result.get("reason").getAsString(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.makeText(CrashActivity.this, getString(R.string.crash_report_cannot_send)+" JsonObject equals null", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Button moreInfoButton = findViewById(R.id.crash_details_btn);
|
||||
moreInfoButton.setOnClickListener(v -> new MaterialDialog.Builder(CrashActivity.this)
|
||||
.title(R.string.crash_details)
|
||||
.content(Html.fromHtml(getErrorString(getIntent(), false)))
|
||||
.typeface(null, "RobotoMono-Regular.ttf")
|
||||
.positiveText(R.string.close)
|
||||
.neutralText(R.string.copy_to_clipboard)
|
||||
.onNeutral((dialog, which) -> copyErrorToClipboard())
|
||||
.show());
|
||||
|
||||
String errorInformation = CustomActivityOnCrash.getAllErrorDetailsFromIntent(CrashActivity.this, getIntent());
|
||||
if (errorInformation.contains("MANUAL CRASH"))
|
||||
{
|
||||
findViewById(R.id.crash_notice).setVisibility(View.GONE);
|
||||
findViewById(R.id.crash_report_btn).setVisibility(View.GONE);
|
||||
findViewById(R.id.crash_feature).setVisibility(View.VISIBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
findViewById(R.id.crash_notice).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.crash_report_btn).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.crash_feature).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private String getErrorString(Intent intent, boolean plain) {
|
||||
// build a string containing the stack trace and the device name + user's registration data
|
||||
String contentPlain = "Crash report:\n\n"+CustomActivityOnCrash.getStackTraceFromIntent(intent);
|
||||
String content = "<small>"+contentPlain+"</small>";
|
||||
content = content.replaceAll(getPackageName(), "<font color='#4caf50'>"+getPackageName()+"</font>");
|
||||
content = content.replaceAll("\n", "<br>");
|
||||
|
||||
contentPlain += "\n"+Build.MANUFACTURER+"\n"+Build.BRAND+"\n"+Build.MODEL+"\n"+Build.DEVICE+"\n";
|
||||
if (app.profile != null && app.profile.getRegistration() == REGISTRATION_ENABLED) {
|
||||
contentPlain += "U: "+app.profile.getUsernameId()+"\nS: "+ app.profile.getStudentNameLong() +"\n";
|
||||
}
|
||||
contentPlain += BuildConfig.VERSION_NAME+" "+BuildConfig.BUILD_TYPE;
|
||||
|
||||
return plain ? contentPlain : content;
|
||||
}
|
||||
|
||||
private void copyErrorToClipboard() {
|
||||
String errorInformation = CustomActivityOnCrash.getAllErrorDetailsFromIntent(CrashActivity.this, getIntent());
|
||||
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
|
||||
//Are there any devices without clipboard...?
|
||||
if (clipboard != null) {
|
||||
ClipData clip = ClipData.newPlainText(getString(R.string.customactivityoncrash_error_activity_error_details_clipboard_label), errorInformation);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(CrashActivity.this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class CrashGtfoActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTheme((((App)getApplication()).getContext()
|
||||
.getSharedPreferences(getString(R.string.preference_file_global), Context.MODE_PRIVATE)
|
||||
.getBoolean("dark_theme", false) ? R.style.AppTheme_Dark : R.style.AppTheme));
|
||||
setContentView(R.layout.activity_gtfo);
|
||||
}
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.gson.Gson;
|
||||
import com.yuyh.jsonviewer.library.JsonRecyclerView;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
public class DebugFragment extends Fragment {
|
||||
App app;
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
app = (App)getActivity().getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_debug, container, false);
|
||||
}
|
||||
|
||||
private static class SimpleObj {
|
||||
Object value;
|
||||
}
|
||||
private static Object target;
|
||||
private static Field targetField = null;
|
||||
private static Object temp;
|
||||
|
||||
private static Object getByPath(App app, Object parent, String path, boolean setGlobal) throws NoSuchMethodException, NoSuchFieldException, InvocationTargetException, IllegalAccessException {
|
||||
Object target = parent;
|
||||
Field targetField = null;
|
||||
List<String> pathList = new ArrayList<>();
|
||||
Matcher matcher = Pattern.compile("(.+?(?:\\(.*?\\))?)\\.").matcher(path+".");
|
||||
while (matcher.find()) {
|
||||
pathList.add(matcher.group(1));
|
||||
}
|
||||
for (String el: pathList) {
|
||||
if (targetField != null) {
|
||||
target = targetField.get(target);
|
||||
targetField = null;
|
||||
}
|
||||
if (el.equals("temp")) {
|
||||
target = temp;
|
||||
continue;
|
||||
}
|
||||
if (el.endsWith(")")) {
|
||||
String methodName = el.substring(0, el.indexOf("("));
|
||||
String parameters = el.substring(el.indexOf("(")+1, el.lastIndexOf(")"));
|
||||
Class[] paramTypes = new Class[]{};
|
||||
Object[] paramValues = new Object[]{};
|
||||
if (!parameters.isEmpty()) {
|
||||
List<Class> paramTypeList = new ArrayList<>();
|
||||
List<Object> paramValueList = new ArrayList<>();
|
||||
for (String parameter: parameters.split(",\\s?")) {
|
||||
if (parameter.equals("null")) {
|
||||
paramTypeList.add(null);
|
||||
paramValueList.add(null);
|
||||
}
|
||||
if (parameter.equals("temp") || (parameter.contains(".") && !parameter.startsWith("\""))) {
|
||||
// this parameter is a path
|
||||
if (parameter.startsWith("app.")) {
|
||||
parameter = parameter.replaceFirst("app\\.", "");
|
||||
}
|
||||
Object param = getByPath(app, app, parameter, false);
|
||||
paramTypeList.add(param.getClass());
|
||||
paramValueList.add(param);
|
||||
continue;
|
||||
}
|
||||
String forceType = null;
|
||||
if (parameter.toLowerCase().endsWith("d")) {
|
||||
forceType = "d";
|
||||
parameter = parameter.substring(0, parameter.length()-1);
|
||||
} else if (parameter.toLowerCase().endsWith("l")) {
|
||||
forceType = "l";
|
||||
parameter = parameter.substring(0, parameter.length()-1);
|
||||
} else if (parameter.toLowerCase().endsWith("f")) {
|
||||
forceType = "f";
|
||||
parameter = parameter.substring(0, parameter.length()-1);
|
||||
} else if (parameter.toLowerCase().endsWith("i")) {
|
||||
forceType = "i";
|
||||
parameter = parameter.substring(0, parameter.length()-1);
|
||||
}
|
||||
SimpleObj obj = app.gson.fromJson("{\"value\":"+parameter+"}", SimpleObj.class);
|
||||
Class type = obj.value.getClass();
|
||||
Object value = obj.value;
|
||||
if ("d".equals(forceType)) {
|
||||
value = Double.valueOf(parameter);
|
||||
type = Double.TYPE;
|
||||
} else if ("l".equals(forceType)) {
|
||||
value = Long.valueOf(parameter);
|
||||
type = Long.TYPE;
|
||||
} else if ("f".equals(forceType)) {
|
||||
value = Float.valueOf(parameter);
|
||||
type = Float.TYPE;
|
||||
} else if ("i".equals(forceType)) {
|
||||
value = Integer.valueOf(parameter);
|
||||
type = Integer.TYPE;
|
||||
}
|
||||
paramTypeList.add(type);
|
||||
paramValueList.add(value);
|
||||
}
|
||||
paramTypes = paramTypeList.toArray(new Class[0]);
|
||||
paramValues = paramValueList.toArray(new Object[0]);
|
||||
}
|
||||
try {
|
||||
Method method = target.getClass().getDeclaredMethod(methodName, paramTypes);
|
||||
method.setAccessible(true);
|
||||
target = method.invoke(target, paramValues);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
Method method = target.getClass().getMethod(methodName, paramTypes);
|
||||
target = method.invoke(target, paramValues);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
targetField = target.getClass().getDeclaredField(el);
|
||||
targetField.setAccessible(true);
|
||||
}
|
||||
catch (NoSuchFieldException e) {
|
||||
targetField = target.getClass().getField(el);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setGlobal) {
|
||||
DebugFragment.target = target;
|
||||
DebugFragment.targetField = targetField;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static String runCommand(App app, String cmdBatch) {
|
||||
for (String cmd: cmdBatch.split(";(?:\\r|\\n|\\r\\n|\\n\\r)?")) {
|
||||
cmd = cmd.trim();
|
||||
if (cmd.isEmpty())
|
||||
continue;
|
||||
|
||||
String[] data;
|
||||
String path;
|
||||
String valueToSet;
|
||||
if (cmd.contains(" = ")) {
|
||||
data = cmd.replaceFirst("run ", "").split(" = ");
|
||||
path = data[0];
|
||||
valueToSet = data[1];
|
||||
} else {
|
||||
path = cmd.replaceFirst("run ", "");
|
||||
valueToSet = null;
|
||||
}
|
||||
|
||||
target = app;
|
||||
try {
|
||||
boolean setToTemp = false;
|
||||
if (path.startsWith("temp=")) {
|
||||
path = path.replaceFirst("temp=", "");
|
||||
setToTemp = true;
|
||||
}
|
||||
if (path.startsWith("app.")) {
|
||||
path = path.replaceFirst("app\\.", "");
|
||||
}
|
||||
getByPath(app, target, path, true);
|
||||
// set the value if specified
|
||||
if (valueToSet != null) {
|
||||
targetField.set(target, app.gson.fromJson(valueToSet, targetField.getGenericType()));
|
||||
targetField = null;
|
||||
}
|
||||
if (targetField != null) {
|
||||
target = targetField.get(target);
|
||||
}
|
||||
if (setToTemp) {
|
||||
temp = target;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Log.getStackTraceString(e);
|
||||
}
|
||||
}
|
||||
return app.gson.toJson(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
getView().findViewById(R.id.debugRegister).setOnClickListener(v -> {
|
||||
String text = ((TextInputEditText) getView().findViewById(R.id.runText)).getText().toString();
|
||||
JsonRecyclerView mRecyclerView = getView().findViewById(R.id.rv_json);
|
||||
String result = runCommand(app, "run " + text);
|
||||
try {
|
||||
mRecyclerView.bindJson(result);
|
||||
}
|
||||
catch (Exception e) {
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title("Result")
|
||||
.content(result)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
}
|
||||
mRecyclerView.setTextSize(20);
|
||||
});
|
||||
getView().findViewById(R.id.debugAppconfig).setOnClickListener(v -> {
|
||||
JsonRecyclerView mRecyclerView = getView().findViewById(R.id.rv_json);
|
||||
// bind json
|
||||
mRecyclerView.bindJson(new Gson().toJson(app.appConfig));
|
||||
mRecyclerView.setTextSize(20);
|
||||
});
|
||||
getView().findViewById(R.id.debugAppprofile).setOnClickListener(v -> {
|
||||
JsonRecyclerView mRecyclerView = getView().findViewById(R.id.rv_json);
|
||||
// bind json
|
||||
mRecyclerView.bindJson(new Gson().toJson(app.profile));
|
||||
mRecyclerView.setTextSize(20);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,363 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityFeedbackBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.FeedbackMessage;
|
||||
import pl.szczodrzynski.edziennik.datamodels.FeedbackMessageWithCount;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.github.bassaer.chatmessageview.model.IChatUser;
|
||||
import com.github.bassaer.chatmessageview.model.Message;
|
||||
import com.github.bassaer.chatmessageview.view.ChatView;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.crc16;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.openUrl;
|
||||
|
||||
public class FeedbackActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "FeedbackActivity";
|
||||
private App app;
|
||||
private ActivityFeedbackBinding b;
|
||||
private boolean firstSend = true;
|
||||
private String deviceToSend = null;
|
||||
private String nameToSend = null;
|
||||
|
||||
private BroadcastReceiver receiver;
|
||||
|
||||
private class User implements IChatUser {
|
||||
Integer id;
|
||||
String name;
|
||||
Bitmap icon;
|
||||
|
||||
public User(int id, String name, Bitmap icon) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getIcon() {
|
||||
return this.icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(Bitmap icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
private User dev;
|
||||
private User user;
|
||||
private ChatView mChatView;
|
||||
|
||||
private void send(String text){
|
||||
/*if ("enable dev mode pls".equals(text)) {
|
||||
try {
|
||||
Log.d(TAG, Utils.AESCrypt.encrypt("ok here you go it's enabled now", "8iryqZUfIUiLmJGi"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}*/
|
||||
MaterialDialog progressDialog = new MaterialDialog.Builder(this)
|
||||
.title(R.string.loading)
|
||||
.content(R.string.sending_message)
|
||||
.negativeText(R.string.cancel)
|
||||
.show();
|
||||
new ServerRequest(app, app.requestScheme + APP_URL + "main.php?feedback_message", "FeedbackSend")
|
||||
.setBodyParameter("message_text", text)
|
||||
.setBodyParameter("target_device", deviceToSend == null ? "null" : deviceToSend)
|
||||
.run(((e, result) -> {
|
||||
progressDialog.dismiss();
|
||||
if (result != null && result.get("success") != null && result.get("success").getAsBoolean()) {
|
||||
FeedbackMessage feedbackMessage = new FeedbackMessage(false, text);
|
||||
if (deviceToSend != null) {
|
||||
feedbackMessage.fromUser = deviceToSend;
|
||||
feedbackMessage.fromUserName = nameToSend;
|
||||
}
|
||||
AsyncTask.execute(() -> app.db.feedbackMessageDao().add(feedbackMessage));
|
||||
Message message = new Message.Builder()
|
||||
.setUser(user)
|
||||
.setRight(true)
|
||||
.setText(feedbackMessage.text)
|
||||
.hideIcon(true)
|
||||
.build();
|
||||
mChatView.send(message);
|
||||
mChatView.setInputText("");
|
||||
b.textInput.setText("");
|
||||
if (firstSend) {
|
||||
Anim.fadeOut(b.inputLayout, 500, new Animation.AnimationListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
b.inputLayout.setVisibility(View.GONE);
|
||||
Anim.fadeIn(b.chatLayout, 500, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
|
||||
}
|
||||
});
|
||||
if (deviceToSend == null) {
|
||||
// we are not the developer
|
||||
FeedbackMessage feedbackMessage2 = new FeedbackMessage(true, "Postaram się jak najszybciej Tobie odpowiedzieć. Dostaniesz powiadomienie o odpowiedzi, która pokaże się w tym miejscu.");
|
||||
AsyncTask.execute(() -> app.db.feedbackMessageDao().add(feedbackMessage2));
|
||||
message = new Message.Builder()
|
||||
.setUser(dev)
|
||||
.setRight(false)
|
||||
.setText(feedbackMessage2.text)
|
||||
.hideIcon(false)
|
||||
.build();
|
||||
mChatView.receive(message);
|
||||
}
|
||||
firstSend = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Toast.makeText(app, "Nie udało się wysłać wiadomości.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void openFaq() {
|
||||
openUrl(this, "http://szkolny.eu/pomoc/");
|
||||
new MaterialDialog.Builder(this)
|
||||
.title(R.string.faq_back_title)
|
||||
.content(R.string.faq_back_text)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog, which) -> {
|
||||
|
||||
}))
|
||||
.onNegative(((dialog, which) -> {
|
||||
|
||||
}))
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTheme(Themes.INSTANCE.getAppTheme());
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_feedback, null, false);
|
||||
setContentView(b.getRoot());
|
||||
app = (App) getApplication();
|
||||
|
||||
setSupportActionBar(b.toolbar);
|
||||
if (getSupportActionBar() != null)
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
b.faqText.setOnClickListener((v -> {
|
||||
openFaq();
|
||||
}));
|
||||
b.faqButton.setOnClickListener((v -> {
|
||||
openFaq();
|
||||
}));
|
||||
|
||||
receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
FeedbackMessage message = app.gson.fromJson(intent.getStringExtra("message"), FeedbackMessage.class);
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(message.sentTime);
|
||||
Message chatMessage = new Message.Builder()
|
||||
.setUser(intent.getStringExtra("type").equals("dev_chat") ? new User(crc16(message.fromUser.getBytes()), message.fromUserName, BitmapFactory.decodeResource(getResources(), R.drawable.ic_account_circle)) : dev)
|
||||
.setRight(!message.received)
|
||||
.setText(message.text)
|
||||
.setSendTime(c)
|
||||
.hideIcon(!message.received)
|
||||
.build();
|
||||
if (message.received)
|
||||
mChatView.receive(chatMessage);
|
||||
else
|
||||
mChatView.send(chatMessage);
|
||||
}
|
||||
};
|
||||
|
||||
mChatView = b.chatView;
|
||||
|
||||
dev = new User(0, "Szkolny.eu", BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
|
||||
user = new User(1, "Ja", BitmapFactory.decodeResource(getResources(), R.drawable.profile));
|
||||
|
||||
//Set UI parameters if you need
|
||||
mChatView.setLeftBubbleColor(Utils.getAttr(this, R.attr.colorSurface));
|
||||
mChatView.setLeftMessageTextColor(Utils.getAttr(this, android.R.attr.textColorPrimary));
|
||||
mChatView.setRightBubbleColor(Utils.getAttr(this, R.attr.colorPrimary));
|
||||
mChatView.setRightMessageTextColor(Color.WHITE);
|
||||
|
||||
//mChatView.setBackgroundColor(ContextCompat.getColor(this, R.color.blueGray500));
|
||||
mChatView.setSendButtonColor(Utils.getAttr(this, R.attr.colorAccent));
|
||||
mChatView.setSendIcon(R.drawable.ic_action_send);
|
||||
//mChatView.setUsernameTextColor(Color.WHITE);
|
||||
//mChatView.setSendTimeTextColor(Color.WHITE);
|
||||
//mChatView.setDateSeparatorColor(Color.WHITE);
|
||||
mChatView.setInputTextHint("Napisz...");
|
||||
//mChatView.setInputTextColor(Color.BLACK);
|
||||
mChatView.setMessageMarginTop(5);
|
||||
mChatView.setMessageMarginBottom(5);
|
||||
|
||||
if (App.devMode && app.deviceId.equals("f054761fbdb6a238")) {
|
||||
b.targetDeviceLayout.setVisibility(View.VISIBLE);
|
||||
b.targetDeviceDropDown.setOnClickListener((v -> {
|
||||
AsyncTask.execute(() -> {
|
||||
List<FeedbackMessageWithCount> messageList = app.db.feedbackMessageDao().getAllWithCountNow();
|
||||
runOnUiThread(() -> {
|
||||
PopupMenu popupMenu = new PopupMenu(this, b.targetDeviceDropDown);
|
||||
int index = 0;
|
||||
for (FeedbackMessageWithCount message: messageList) {
|
||||
popupMenu.getMenu().add(0, index, index, message.fromUserName+" - "+message.fromUser+" ("+message.messageCount+")");
|
||||
index++;
|
||||
}
|
||||
popupMenu.setOnMenuItemClickListener(item -> {
|
||||
b.targetDeviceDropDown.setText(item.getTitle());
|
||||
mChatView.getMessageView().removeAll();
|
||||
FeedbackMessageWithCount message = messageList.get(item.getItemId());
|
||||
deviceToSend = message.fromUser;
|
||||
nameToSend = message.fromUserName;
|
||||
AsyncTask.execute(() -> {
|
||||
List<FeedbackMessage> messageList2 = app.db.feedbackMessageDao().getAllByUserNow(deviceToSend);
|
||||
runOnUiThread(() -> {
|
||||
b.chatLayout.setVisibility(View.VISIBLE);
|
||||
b.inputLayout.setVisibility(View.GONE);
|
||||
for (FeedbackMessage message2 : messageList2) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(message2.sentTime);
|
||||
Message chatMessage = new Message.Builder()
|
||||
.setUser(message2.received ? new User(crc16(message2.fromUser.getBytes()), message2.fromUserName, BitmapFactory.decodeResource(getResources(), R.drawable.ic_account_circle)) : user)
|
||||
.setRight(!message2.received)
|
||||
.setText(message2.text)
|
||||
.setSendTime(c)
|
||||
.hideIcon(!message2.received)
|
||||
.build();
|
||||
if (message2.received)
|
||||
mChatView.receive(chatMessage);
|
||||
else
|
||||
mChatView.send(chatMessage);
|
||||
}
|
||||
});
|
||||
});
|
||||
return false;
|
||||
});
|
||||
popupMenu.show();
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
else {
|
||||
AsyncTask.execute(() -> {
|
||||
List<FeedbackMessage> messageList = app.db.feedbackMessageDao().getAllNow();
|
||||
firstSend = messageList.size() == 0;
|
||||
runOnUiThread(() -> {
|
||||
if (firstSend) {
|
||||
openFaq();
|
||||
b.chatLayout.setVisibility(View.GONE);
|
||||
b.inputLayout.setVisibility(View.VISIBLE);
|
||||
b.sendButton.setOnClickListener((v -> {
|
||||
if (b.textInput.getText() == null || b.textInput.getText().length() == 0) {
|
||||
Toast.makeText(app, "Podaj treść wiadomości.", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
send(b.textInput.getText().toString());
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
/*new MaterialDialog.Builder(this)
|
||||
.title(R.string.faq)
|
||||
.content(R.string.faq_text)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog, which) -> {
|
||||
openFaq();
|
||||
}))
|
||||
.show();*/
|
||||
b.chatLayout.setVisibility(View.VISIBLE);
|
||||
b.inputLayout.setVisibility(View.GONE);
|
||||
}
|
||||
for (FeedbackMessage message : messageList) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(message.sentTime);
|
||||
Message chatMessage = new Message.Builder()
|
||||
.setUser(message.fromUser != null ? new User(crc16(message.fromUser.getBytes()), message.fromUserName, BitmapFactory.decodeResource(getResources(), R.drawable.ic_account_circle)) : message.received ? dev : user)
|
||||
.setRight(!message.received)
|
||||
.setText(message.text)
|
||||
.setSendTime(c)
|
||||
.hideIcon(!message.received)
|
||||
.build();
|
||||
if (message.received)
|
||||
mChatView.receive(chatMessage);
|
||||
else
|
||||
mChatView.send(chatMessage);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//Click Send Button
|
||||
mChatView.setOnClickSendButtonListener(view -> {
|
||||
send(mChatView.getInputText());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) // Press Back Icon
|
||||
{
|
||||
finish();
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
registerReceiver(receiver, new IntentFilter("pl.szczodrzynski.edziennik.ui.modules.base.FeedbackActivity"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver(receiver);
|
||||
}
|
||||
}
|
@ -0,0 +1,334 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.github.bassaer.chatmessageview.model.IChatUser
|
||||
import com.github.bassaer.chatmessageview.model.Message
|
||||
import com.github.bassaer.chatmessageview.view.ChatView
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentFeedbackBinding
|
||||
import pl.szczodrzynski.edziennik.datamodels.FeedbackMessage
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
import pl.szczodrzynski.edziennik.utils.Anim
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc16
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.openUrl
|
||||
import java.util.*
|
||||
|
||||
class FeedbackFragment : Fragment() {
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentFeedbackBinding
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = FragmentFeedbackBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
b.faqText.setOnClickListener { v -> openFaq() }
|
||||
b.faqButton.setOnClickListener { v -> openFaq() }
|
||||
|
||||
receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val message = app.gson.fromJson(intent.getStringExtra("message"), FeedbackMessage::class.java)
|
||||
val c = Calendar.getInstance()
|
||||
c.timeInMillis = message.sentTime
|
||||
val chatMessage = Message.Builder()
|
||||
.setUser(
|
||||
if (intent.getStringExtra("type") == "dev_chat")
|
||||
User(crc16(message.fromUser.toByteArray()), message.fromUserName, BitmapFactory.decodeResource(resources, R.drawable.ic_account_circle))
|
||||
else
|
||||
dev)
|
||||
.setRight(!message.received)
|
||||
.setText(message.text)
|
||||
.setSendTime(c)
|
||||
.hideIcon(!message.received)
|
||||
.build()
|
||||
if (message.received)
|
||||
mChatView.receive(chatMessage)
|
||||
else
|
||||
mChatView.send(chatMessage)
|
||||
}
|
||||
}
|
||||
|
||||
//Set UI parameters if you need
|
||||
mChatView.setLeftBubbleColor(Utils.getAttr(activity, R.attr.colorSurface))
|
||||
mChatView.setLeftMessageTextColor(Utils.getAttr(activity, android.R.attr.textColorPrimary))
|
||||
mChatView.setRightBubbleColor(Utils.getAttr(activity, R.attr.colorPrimary))
|
||||
mChatView.setRightMessageTextColor(Color.WHITE)
|
||||
|
||||
//mChatView.setBackgroundColor(ContextCompat.getColor(this, R.color.blueGray500));
|
||||
mChatView.setSendButtonColor(Utils.getAttr(activity, R.attr.colorAccent))
|
||||
mChatView.setSendIcon(R.drawable.ic_action_send)
|
||||
//mChatView.setUsernameTextColor(Color.WHITE);
|
||||
//mChatView.setSendTimeTextColor(Color.WHITE);
|
||||
//mChatView.setDateSeparatorColor(Color.WHITE);
|
||||
mChatView.setInputTextHint("Napisz...")
|
||||
//mChatView.setInputTextColor(Color.BLACK);
|
||||
mChatView.setMessageMarginTop(5)
|
||||
mChatView.setMessageMarginBottom(5)
|
||||
|
||||
if (App.devMode && app.deviceId == "f054761fbdb6a238") {
|
||||
b.targetDeviceLayout.visibility = View.VISIBLE
|
||||
b.targetDeviceDropDown.setOnClickListener { v ->
|
||||
AsyncTask.execute {
|
||||
val messageList = app.db.feedbackMessageDao().allWithCountNow
|
||||
activity.runOnUiThread {
|
||||
val popupMenu = PopupMenu(activity, b.targetDeviceDropDown)
|
||||
var index = 0
|
||||
for (message in messageList) {
|
||||
popupMenu.menu.add(0, index, index, message.fromUserName + " - " + message.fromUser + " (" + message.messageCount + ")")
|
||||
index++
|
||||
}
|
||||
popupMenu.setOnMenuItemClickListener { item ->
|
||||
b.targetDeviceDropDown.setText(item.title)
|
||||
mChatView.getMessageView().removeAll()
|
||||
val message = messageList[item.itemId]
|
||||
deviceToSend = message.fromUser
|
||||
nameToSend = message.fromUserName
|
||||
AsyncTask.execute {
|
||||
val messageList2 = app.db.feedbackMessageDao().getAllByUserNow(deviceToSend)
|
||||
activity.runOnUiThread {
|
||||
b.chatLayout.visibility = View.VISIBLE
|
||||
b.inputLayout.visibility = View.GONE
|
||||
for (message2 in messageList2) {
|
||||
val c = Calendar.getInstance()
|
||||
c.timeInMillis = message2.sentTime
|
||||
val chatMessage = Message.Builder()
|
||||
.setUser(if (message2.received) User(crc16(message2.fromUser.toByteArray()), message2.fromUserName, BitmapFactory.decodeResource(resources, R.drawable.ic_account_circle)) else user)
|
||||
.setRight(!message2.received)
|
||||
.setText(message2.text)
|
||||
.setSendTime(c)
|
||||
.hideIcon(!message2.received)
|
||||
.build()
|
||||
if (message2.received)
|
||||
mChatView.receive(chatMessage)
|
||||
else
|
||||
mChatView.send(chatMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
popupMenu.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AsyncTask.execute {
|
||||
val messageList = app.db.feedbackMessageDao().allNow
|
||||
firstSend = messageList.size == 0
|
||||
activity.runOnUiThread {
|
||||
if (firstSend) {
|
||||
openFaq()
|
||||
b.chatLayout.visibility = View.GONE
|
||||
b.inputLayout.visibility = View.VISIBLE
|
||||
b.sendButton.setOnClickListener { v ->
|
||||
if (b.textInput.text == null || b.textInput.text!!.length == 0) {
|
||||
Toast.makeText(app, "Podaj treść wiadomości.", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
send(b.textInput.text!!.toString())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*new MaterialDialog.Builder(this)
|
||||
.title(R.string.faq)
|
||||
.content(R.string.faq_text)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog, which) -> {
|
||||
openFaq();
|
||||
}))
|
||||
.show();*/
|
||||
b.chatLayout.visibility = View.VISIBLE
|
||||
b.inputLayout.visibility = View.GONE
|
||||
}
|
||||
for (message in messageList) {
|
||||
val c = Calendar.getInstance()
|
||||
c.timeInMillis = message.sentTime
|
||||
val chatMessage = Message.Builder()
|
||||
.setUser(if (message.fromUser != null) User(crc16(message.fromUser.toByteArray()), message.fromUserName, BitmapFactory.decodeResource(resources, R.drawable.ic_account_circle)) else if (message.received) dev else user)
|
||||
.setRight(!message.received)
|
||||
.setText(message.text)
|
||||
.setSendTime(c)
|
||||
.hideIcon(!message.received)
|
||||
.build()
|
||||
if (message.received)
|
||||
mChatView.receive(chatMessage)
|
||||
else
|
||||
mChatView.send(chatMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Click Send Button
|
||||
mChatView.setOnClickSendButtonListener(View.OnClickListener { send(mChatView.inputText) })
|
||||
}
|
||||
|
||||
private var firstSend = true
|
||||
private var deviceToSend: String? = null
|
||||
private var nameToSend: String? = null
|
||||
|
||||
private var receiver: BroadcastReceiver? = null
|
||||
|
||||
class User(internal var id: Int?, internal var name: String, internal var icon: Bitmap) : IChatUser {
|
||||
|
||||
override fun getId(): String {
|
||||
return this.id!!.toString()
|
||||
}
|
||||
|
||||
override fun getName(): String? {
|
||||
return this.name
|
||||
}
|
||||
|
||||
override fun getIcon(): Bitmap? {
|
||||
return this.icon
|
||||
}
|
||||
|
||||
override fun setIcon(icon: Bitmap) {
|
||||
this.icon = icon
|
||||
}
|
||||
}
|
||||
|
||||
private val dev: User by lazy {
|
||||
User(0, "Szkolny.eu", BitmapFactory.decodeResource(activity.resources, R.mipmap.ic_splash))
|
||||
}
|
||||
private val user: User by lazy {
|
||||
User(1, "Ja", BitmapFactory.decodeResource(activity.resources, R.drawable.profile_))
|
||||
}
|
||||
private val mChatView: ChatView by lazy {
|
||||
b.chatView
|
||||
}
|
||||
|
||||
private fun send(text: String) {
|
||||
/*if ("enable dev mode pls".equals(text)) {
|
||||
try {
|
||||
Log.d(TAG, Utils.AESCrypt.encrypt("ok here you go it's enabled now", "8iryqZUfIUiLmJGi"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}*/
|
||||
val progressDialog = MaterialDialog.Builder(activity)
|
||||
.title(R.string.loading)
|
||||
.content(R.string.sending_message)
|
||||
.negativeText(R.string.cancel)
|
||||
.show()
|
||||
ServerRequest(app, app.requestScheme + APP_URL + "main.php?feedback_message", "FeedbackSend")
|
||||
.setBodyParameter("message_text", text)
|
||||
.setBodyParameter("target_device", if (deviceToSend == null) "null" else deviceToSend)
|
||||
.run { e, result ->
|
||||
progressDialog.dismiss()
|
||||
if (result != null && result.get("success") != null && result.get("success").asBoolean) {
|
||||
val feedbackMessage = FeedbackMessage(false, text)
|
||||
if (deviceToSend != null) {
|
||||
feedbackMessage.fromUser = deviceToSend
|
||||
feedbackMessage.fromUserName = nameToSend
|
||||
}
|
||||
AsyncTask.execute { app.db.feedbackMessageDao().add(feedbackMessage) }
|
||||
var message = Message.Builder()
|
||||
.setUser(user!!)
|
||||
.setRight(true)
|
||||
.setText(feedbackMessage.text)
|
||||
.hideIcon(true)
|
||||
.build()
|
||||
mChatView!!.send(message)
|
||||
mChatView!!.inputText = ""
|
||||
b.textInput.setText("")
|
||||
if (firstSend) {
|
||||
Anim.fadeOut(b.inputLayout, 500, object : Animation.AnimationListener {
|
||||
override fun onAnimationStart(animation: Animation) {
|
||||
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
b.inputLayout.visibility = View.GONE
|
||||
Anim.fadeIn(b.chatLayout, 500, null)
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animation) {
|
||||
|
||||
}
|
||||
})
|
||||
if (deviceToSend == null) {
|
||||
// we are not the developer
|
||||
val feedbackMessage2 = FeedbackMessage(true, "Postaram się jak najszybciej Tobie odpowiedzieć. Dostaniesz powiadomienie o odpowiedzi, która pokaże się w tym miejscu.")
|
||||
AsyncTask.execute { app.db.feedbackMessageDao().add(feedbackMessage2) }
|
||||
message = Message.Builder()
|
||||
.setUser(dev!!)
|
||||
.setRight(false)
|
||||
.setText(feedbackMessage2.text)
|
||||
.hideIcon(false)
|
||||
.build()
|
||||
mChatView!!.receive(message)
|
||||
}
|
||||
firstSend = false
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(app, "Nie udało się wysłać wiadomości.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFaq() {
|
||||
openUrl(activity, "http://szkolny.eu/pomoc/")
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.faq_back_title)
|
||||
.content(R.string.faq_back_text)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive { dialog, which ->
|
||||
|
||||
}
|
||||
.onNegative { dialog, which ->
|
||||
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (receiver != null)
|
||||
activity.registerReceiver(receiver, IntentFilter("pl.szczodrzynski.edziennik.ui.modules.base.FeedbackActivity"))
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (receiver != null)
|
||||
activity.unregisterReceiver(receiver)
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHelpBinding
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class HelpFragment : Fragment() {
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentHelpBinding
|
||||
/*
|
||||
private val navController: NavController by lazy { Navigation.findNavController(b.root) }
|
||||
*/
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = FragmentHelpBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoadingBinding
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class LoadingFragment : Fragment() {
|
||||
|
||||
private lateinit var b: FragmentLoadingBinding
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
if (context == null)
|
||||
return null
|
||||
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||
// activity, context and profile is valid
|
||||
b = FragmentLoadingBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.Navigation
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentTemplateBinding
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class TemplateFragment : Fragment() {
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentTemplateBinding
|
||||
private val navController: NavController by lazy { Navigation.findNavController(b.root) }
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = FragmentTemplateBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.grades;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Grade;
|
||||
import pl.szczodrzynski.edziennik.datamodels.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.COLOR_MODE_DEFAULT;
|
||||
|
||||
public class GradesListAdapter extends RecyclerView.Adapter<GradesListAdapter.ViewHolder> {
|
||||
private Context mContext;
|
||||
private List<GradeFull> gradeList;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public GradesListAdapter(Context mCtx, List<GradeFull> gradeList) {
|
||||
this.mContext = mCtx;
|
||||
this.gradeList = gradeList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GradesListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
View view = inflater.inflate(R.layout.row_grades_list_item, parent, false);
|
||||
return new GradesListAdapter.ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GradesListAdapter.ViewHolder holder, int position) {
|
||||
App app = (App) mContext.getApplicationContext();
|
||||
|
||||
GradeFull grade = gradeList.get(position);
|
||||
|
||||
holder.root.setOnClickListener((v -> {
|
||||
new GradeDetailsDialog(v.getContext(), App.profileId).show(app, grade);
|
||||
}));
|
||||
|
||||
int gradeColor;
|
||||
if (app.profile.getGradeColorMode() == COLOR_MODE_DEFAULT) {
|
||||
gradeColor = grade.color;
|
||||
}
|
||||
else {
|
||||
gradeColor = Colors.gradeToColor(grade);
|
||||
}
|
||||
|
||||
holder.gradesListName.setText(grade.name);
|
||||
holder.gradesListName.setSelected(true);
|
||||
holder.gradesListName.setTypeface(null, Typeface.BOLD);
|
||||
holder.gradesListName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.25 ? 0xff000000 : 0xffffffff);
|
||||
holder.gradesListName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY));
|
||||
|
||||
if (grade.description.trim().isEmpty()) {
|
||||
holder.gradesListDescription.setText(grade.category);
|
||||
holder.gradesListCategory.setText(grade.isImprovement ? app.getString(R.string.grades_improvement_category_format, "") : "");
|
||||
}
|
||||
else {
|
||||
holder.gradesListDescription.setText(grade.description);
|
||||
holder.gradesListCategory.setText(grade.isImprovement ? app.getString(R.string.grades_improvement_category_format, grade.category) : grade.category);
|
||||
}
|
||||
|
||||
DecimalFormat format = new DecimalFormat("#.##");
|
||||
DecimalFormat formatWithZeroes = new DecimalFormat("#.00");
|
||||
|
||||
if (grade.weight < 0) {
|
||||
grade.weight *= -1;
|
||||
}
|
||||
if (grade.type == Grade.TYPE_DESCRIPTIVE || grade.type == Grade.TYPE_TEXT || grade.type == Grade.TYPE_BEHAVIOUR) {
|
||||
holder.gradesListWeight.setVisibility(View.GONE);
|
||||
grade.weight = 0;
|
||||
}
|
||||
else {
|
||||
holder.gradesListWeight.setVisibility(View.VISIBLE);
|
||||
if (grade.type == Grade.TYPE_POINT) {
|
||||
holder.gradesListWeight.setText(app.getString(R.string.grades_max_points_format, format.format(grade.valueMax)));
|
||||
}
|
||||
else if (grade.weight == 0) {
|
||||
holder.gradesListWeight.setText(app.getString(R.string.grades_weight_not_counted));
|
||||
}
|
||||
else {
|
||||
holder.gradesListWeight.setText(app.getString(R.string.grades_weight_format, format.format(grade.weight) + (grade.classAverage != -1 ? ", " + formatWithZeroes.format(grade.classAverage) : "")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
holder.gradesListTeacher.setText(grade.teacherFullName);
|
||||
holder.gradesListAddedDate.setText(Date.fromMillis(grade.addedDate).getFormattedStringShort());
|
||||
|
||||
if (!grade.seen) {
|
||||
holder.gradesListDescription.setBackground(mContext.getResources().getDrawable(R.drawable.bg_rounded_4dp));
|
||||
holder.gradesListDescription.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
else {
|
||||
holder.gradesListDescription.setBackground(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return gradeList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
View root;
|
||||
TextView gradesListName;
|
||||
TextView gradesListDescription;
|
||||
TextView gradesListCategory;
|
||||
TextView gradesListWeight;
|
||||
TextView gradesListTeacher;
|
||||
TextView gradesListAddedDate;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
root = itemView.getRootView();
|
||||
gradesListName = itemView.findViewById(R.id.gradesListName);
|
||||
gradesListDescription = itemView.findViewById(R.id.gradesListCategoryColumn);
|
||||
gradesListCategory = itemView.findViewById(R.id.gradesListCategoryDescription);
|
||||
gradesListWeight = itemView.findViewById(R.id.gradesListWeight);
|
||||
gradesListTeacher = itemView.findViewById(R.id.gradesListTeacher);
|
||||
gradesListAddedDate = itemView.findViewById(R.id.gradesListAddedDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,785 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.grades;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.widget.NestedScrollView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mikepenz.iconics.view.IconicsImageView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.datamodels.AppDb;
|
||||
import pl.szczodrzynski.edziennik.datamodels.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Subject;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListAdapter;
|
||||
import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
import static pl.szczodrzynski.edziennik.MainActivity.TARGET_GRADES_EDITOR;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.COLOR_MODE_DEFAULT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_AVG_2_SEM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_SEM_2_AVG;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_SEM_2_SEM;
|
||||
|
||||
public class GradesSubjectAdapter extends ArrayAdapter<ItemGradesSubjectModel> implements View.OnClickListener {
|
||||
private static final String TAG = "GradesSubjectAdapter";
|
||||
private MainActivity activity;
|
||||
public List<ItemGradesSubjectModel> subjectList;
|
||||
|
||||
private void updateBadges(Context context, ItemGradesSubjectModel model) {
|
||||
// do not need this since we have an Observer for unread counters..
|
||||
//((App)getContext().getApplicationContext()).saveRegister(); // I don't like this.
|
||||
}
|
||||
|
||||
private boolean invalidAvg(float avg) {
|
||||
return avg == 0.0f || Float.isNaN(avg);
|
||||
}
|
||||
|
||||
private void updateSubjectSemesterBadges(ViewHolder holder, ItemGradesSubjectModel model) {
|
||||
if (model.semester1Unread > 0 || model.semester2Unread > 0) {
|
||||
holder.gradesSubjectTitle.setBackground(getContext().getResources().getDrawable(R.drawable.bg_rounded_4dp));
|
||||
holder.gradesSubjectTitle.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectTitle.setBackground(null);
|
||||
}
|
||||
if (model.semester1Unread > 0) {
|
||||
holder.gradesSubjectSemester1Title.setBackground(getContext().getResources().getDrawable(R.drawable.bg_rounded_4dp));
|
||||
holder.gradesSubjectSemester1Title.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester1Title.setBackground(null);
|
||||
}
|
||||
if (model.semester2Unread > 0) {
|
||||
holder.gradesSubjectSemester2Title.setBackground(getContext().getResources().getDrawable(R.drawable.bg_rounded_4dp));
|
||||
holder.gradesSubjectSemester2Title.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester2Title.setBackground(null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean gradesSetAsRead(ViewHolder holder, ItemGradesSubjectModel model, int semester) {
|
||||
boolean somethingChanged = false;
|
||||
AppDb db = AppDb.getDatabase(null);
|
||||
if (semester == 1) {
|
||||
model.semester1Unread = 0;
|
||||
for (GradeFull grade : model.grades1) {
|
||||
if (!grade.seen) {
|
||||
db.metadataDao().setSeen(App.profileId, grade, somethingChanged = true);
|
||||
}
|
||||
}
|
||||
if (model.semester1Proposed != null && !model.semester1Proposed.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester1Proposed, somethingChanged = true);
|
||||
if (model.semester1Final != null && !model.semester1Final.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester1Final, somethingChanged = true);
|
||||
}
|
||||
else if (semester == 2) {
|
||||
model.semester2Unread = 0;
|
||||
for (GradeFull grade : model.grades2) {
|
||||
if (!grade.seen) {
|
||||
db.metadataDao().setSeen(App.profileId, grade, somethingChanged = true);
|
||||
}
|
||||
}
|
||||
if (model.semester2Proposed != null && !model.semester2Proposed.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester2Proposed, somethingChanged = true);
|
||||
if (model.semester2Final != null && !model.semester2Final.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester2Final, somethingChanged = true);
|
||||
if (model.yearProposed != null && !model.yearProposed.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.yearProposed, somethingChanged = true);
|
||||
if (model.yearFinal != null && !model.yearFinal.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.yearFinal, somethingChanged = true);
|
||||
}
|
||||
if (somethingChanged) updateSubjectSemesterBadges(holder, model);
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
private void expandSubject(ViewHolder holder, ItemGradesSubjectModel model) {
|
||||
Anim.fadeOut(holder.gradesSubjectPreviewContainer, 200, new Animation.AnimationListener() {
|
||||
@Override public void onAnimationStart(Animation animation) { }
|
||||
@Override public void onAnimationRepeat(Animation animation) { }
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
boolean somethingChanged = false;
|
||||
if (holder.gradesSubjectSemester1Container.getVisibility() != View.GONE) {
|
||||
somethingChanged = gradesSetAsRead(holder, model, 1);
|
||||
}
|
||||
if (holder.gradesSubjectSemester2Container.getVisibility() != View.GONE) {
|
||||
somethingChanged = gradesSetAsRead(holder, model, 2);
|
||||
}
|
||||
if (somethingChanged) updateBadges(getContext(), model);
|
||||
//holder.gradesSubjectPreviewContent.setVisibility(View.INVISIBLE);
|
||||
Anim.expand(holder.gradesSubjectContent, 500, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void collapseSubject(ViewHolder holder, ItemGradesSubjectModel model) {
|
||||
Anim.collapse(holder.gradesSubjectContent, 500, new Animation.AnimationListener() {
|
||||
@Override public void onAnimationStart(Animation animation) { }
|
||||
@Override public void onAnimationRepeat(Animation animation) { }
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
//holder.gradesSubjectPreviewContent.setVisibility(View.VISIBLE);
|
||||
Anim.fadeIn(holder.gradesSubjectPreviewContainer, 200, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class BuildGradeViews extends AsyncTask<Void, Void, Void> {
|
||||
boolean findViews;
|
||||
ItemGradesSubjectModel model;
|
||||
//ViewGroup parent;
|
||||
//int position;
|
||||
ViewHolder holder;
|
||||
|
||||
BuildGradeViews(ItemGradesSubjectModel model, ViewHolder holder, ViewGroup parent, int position, boolean findViews) {
|
||||
this.model = model;
|
||||
this.holder = holder;
|
||||
this.findViews = findViews;
|
||||
//this.parent = parent;
|
||||
//this.position = position;
|
||||
}
|
||||
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (this.findViews) {
|
||||
findViews(holder, holder.gradesSubjectRoot);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
DecimalFormat df = new DecimalFormat("#.00");
|
||||
if (this.findViews) {
|
||||
// TODO NIE WIEM CO TO ROBI XD
|
||||
//this.viewHolder.semestrTitle1.setText(C0193R.string.semestr1);
|
||||
//this.viewHolder.semestrTitle2.setText(C0193R.string.semestr2);
|
||||
/*if (GradesSubjectAdapter.this.columns == 0) {
|
||||
DisplayMetrics metrics = GradeListAdapterBySubject.this.context.getResources().getDisplayMetrics();
|
||||
if (GradeListAdapterBySubject.this.context.getResources().getBoolean(C0193R.bool.tablet)) {
|
||||
GradeListAdapterBySubject.this.columns = ((int) ((((float) (this.parent.getWidth() / 2)) / metrics.density) - 30.0f)) / 58;
|
||||
} else {
|
||||
GradeListAdapterBySubject.this.columns = ((int) ((((float) this.parent.getWidth()) / metrics.density) - 30.0f)) / 58;
|
||||
}
|
||||
}
|
||||
this.viewHolder.semestrGridView1.setColumnCount(GradeListAdapterBySubject.this.columns);
|
||||
this.viewHolder.semestrGridView2.setColumnCount(GradeListAdapterBySubject.this.columns);*/
|
||||
}
|
||||
if (model != null && model.subject != null && model.subject.id != holder.lastSubject) {
|
||||
holder.gradesSubjectRoot.setBackground(Colors.getAdaptiveBackgroundDrawable(model.subject.color, model.subject.color));
|
||||
updateSubjectSemesterBadges(holder, model);
|
||||
holder.gradesSubjectTitle.setText(model.subject.longName);
|
||||
holder.gradesSubjectPreviewContent.removeAllViews();
|
||||
|
||||
if (model.expandView) {
|
||||
// commented is without animations, do not use now (with unread badges)
|
||||
//holder.gradesSubjectContent.setVisibility(View.VISIBLE);
|
||||
//holder.gradesSubjectPreviewContent.setVisibility(View.INVISIBLE);
|
||||
expandSubject(holder, model);
|
||||
model.expandView = false;
|
||||
}
|
||||
int showSemester = model.profile.getCurrentSemester();
|
||||
|
||||
List<GradeFull> gradeList = (showSemester == 1 ? model.grades1 : model.grades2);
|
||||
if (gradeList.size() == 0) {
|
||||
showSemester = (showSemester == 1 ? 2 : 1);
|
||||
gradeList = (showSemester == 1 ? model.grades1 : model.grades2);
|
||||
}
|
||||
|
||||
App app = (App) getContext().getApplicationContext();
|
||||
|
||||
float scale = getContext().getResources().getDisplayMetrics().density;
|
||||
int _5dp = (int) (5 * scale + 0.5f);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
|
||||
layoutParams.setMargins(0, 0, _5dp, 0);
|
||||
|
||||
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
|
||||
int maxWidthPx = displayMetrics.widthPixels - Utils.dpToPx((app.appConfig.miniDrawerVisible ? 72 : 0)/*miniDrawer size*/ + 8 + 8/*left and right offsets*/ + 24/*ellipsize width*/);
|
||||
int totalWidthPx = 0;
|
||||
boolean ellipsized = false;
|
||||
|
||||
if (showSemester != model.profile.getCurrentSemester()) {
|
||||
// showing different semester, because of no grades in the selected one
|
||||
holder.gradesSubjectPreviewSemester.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewSemester.setText(getContext().getString(R.string.grades_semester_header_format, showSemester));
|
||||
// decrease the max preview width. DONE below
|
||||
/*holder.gradesSubjectPreviewSemester.measure(WRAP_CONTENT, WRAP_CONTENT);
|
||||
maxWidthPx -= holder.gradesSubjectPreviewSemester.getMeasuredWidth();
|
||||
maxWidthPx -= _5dp;*/
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectPreviewSemester.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
if (model.grades1.size() > 0) {
|
||||
holder.gradesSubjectSemester1Nest.setNestedScrollingEnabled(false);
|
||||
holder.gradesSubjectSemester1Content.setHasFixedSize(false);
|
||||
holder.gradesSubjectSemester1Content.setNestedScrollingEnabled(false);
|
||||
holder.gradesSubjectSemester1Content.setLayoutManager(new LinearLayoutManager(activity));
|
||||
holder.gradesSubjectSemester1Content.setAdapter(new GradesListAdapter(activity, model.grades1));
|
||||
holder.gradesSubjectSemester1Header.setVisibility(View.VISIBLE);
|
||||
if (showSemester == 1) {
|
||||
holder.gradesSubjectSemester1Container.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester1Container.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (model.isDescriptiveSubject && !model.isNormalSubject && !model.isPointSubject && !model.isBehaviourSubject) {
|
||||
holder.gradesSubjectPreviewAverage.setVisibility(View.GONE);
|
||||
holder.gradesSubjectSemester1Average.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectPreviewAverage.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester1Average.setVisibility(View.VISIBLE);
|
||||
int formatSingle = (model.isPointSubject ? R.string.grades_average_single_percent_format : model.isBehaviourSubject ? R.string.grades_average_single_point_format : R.string.grades_average_single_format);
|
||||
int format = (model.isPointSubject ? R.string.grades_semester_average_percent_format : model.isBehaviourSubject ? R.string.grades_semester_average_point_format : R.string.grades_semester_average_format);
|
||||
// PREVIEW AVERAGE
|
||||
if (showSemester == 1) {
|
||||
holder.gradesSubjectPreviewAverage.setText(
|
||||
getContext().getString(
|
||||
formatSingle,
|
||||
invalidAvg(model.semester1Average) ? "-" : df.format(model.semester1Average)
|
||||
)
|
||||
);
|
||||
}
|
||||
// AVERAGE value
|
||||
holder.gradesSubjectSemester1Average.setText(
|
||||
getContext().getString(
|
||||
format,
|
||||
1,
|
||||
invalidAvg(model.semester1Average) ? "-" : df.format(model.semester1Average)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// PROPOSED grade
|
||||
if (model.semester1Proposed != null) {
|
||||
holder.gradesSubjectSemester1Proposed.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester1Proposed.setText(model.semester1Proposed.name);
|
||||
holder.gradesSubjectSemester1Proposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Proposed.name), PorterDuff.Mode.MULTIPLY));
|
||||
holder.gradesSubjectSemester1Proposed.setTextColor(Colors.gradeNameToColor(model.semester1Proposed.name));
|
||||
if (showSemester == 1) {
|
||||
holder.gradesSubjectPreviewProposed.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewProposed.setText(model.semester1Proposed.name);
|
||||
holder.gradesSubjectPreviewProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Proposed.name), PorterDuff.Mode.MULTIPLY));
|
||||
holder.gradesSubjectPreviewProposed.setTextColor(Colors.gradeNameToColor(model.semester1Proposed.name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester1Proposed.setVisibility(View.GONE);
|
||||
if (showSemester == 1) {
|
||||
holder.gradesSubjectPreviewProposed.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
// FINAL grade
|
||||
if (model.semester1Final != null) {
|
||||
holder.gradesSubjectSemester1Final.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester1Final.setText(model.semester1Final.name);
|
||||
holder.gradesSubjectSemester1Final.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Final.name), PorterDuff.Mode.MULTIPLY));
|
||||
if (showSemester == 1) {
|
||||
holder.gradesSubjectPreviewFinal.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewFinal.setText(model.semester1Final.name);
|
||||
holder.gradesSubjectPreviewFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Final.name), PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester1Final.setVisibility(View.GONE);
|
||||
if (showSemester == 1) {
|
||||
holder.gradesSubjectPreviewFinal.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester1Header.setVisibility(View.GONE);
|
||||
holder.gradesSubjectSemester1Container.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (model.grades2.size() > 0) {
|
||||
holder.gradesSubjectSemester2Nest.setNestedScrollingEnabled(false);
|
||||
holder.gradesSubjectSemester2Content.setHasFixedSize(false);
|
||||
holder.gradesSubjectSemester2Content.setNestedScrollingEnabled(false);
|
||||
holder.gradesSubjectSemester2Content.setLayoutManager(new LinearLayoutManager(activity));
|
||||
holder.gradesSubjectSemester2Content.setAdapter(new GradesListAdapter(activity, model.grades2));
|
||||
holder.gradesSubjectSemester2Header.setVisibility(View.VISIBLE);
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectSemester2Container.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester2Container.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (model.isDescriptiveSubject && !model.isNormalSubject && !model.isPointSubject && !model.isBehaviourSubject) {
|
||||
holder.gradesSubjectPreviewAverage.setVisibility(View.GONE);
|
||||
holder.gradesSubjectSemester2Average.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectPreviewAverage.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester2Average.setVisibility(View.VISIBLE);
|
||||
// PREVIEW AVERAGE
|
||||
int formatDouble = (model.isPointSubject ? R.string.grades_average_double_percent_format : model.isBehaviourSubject ? R.string.grades_average_double_point_format : R.string.grades_average_double_format);
|
||||
int format = (model.isPointSubject ? R.string.grades_semester_average_percent_format : model.isBehaviourSubject ? R.string.grades_semester_average_point_format : R.string.grades_semester_average_format);
|
||||
if (showSemester == 2) {
|
||||
if (model.semester2Proposed != null || model.semester2Final != null) {
|
||||
holder.gradesSubjectPreviewAverage.setText(invalidAvg(model.semester2Average) ? "-" : df.format(model.semester2Average));
|
||||
holder.gradesSubjectPreviewYearAverage.setText(invalidAvg(model.yearAverage) ? "-" : df.format(model.yearAverage));
|
||||
holder.gradesSubjectPreviewYearAverage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectPreviewAverage.setText(
|
||||
getContext().getString(
|
||||
formatDouble,
|
||||
invalidAvg(model.semester2Average) ? "-" : df.format(model.semester2Average),
|
||||
invalidAvg(model.yearAverage) ? "-" : df.format(model.yearAverage)
|
||||
)
|
||||
);
|
||||
holder.gradesSubjectPreviewYearAverage.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
// AVERAGE value
|
||||
holder.gradesSubjectSemester2Average.setText(
|
||||
getContext().getString(
|
||||
format,
|
||||
2,
|
||||
invalidAvg(model.semester2Average) ? "-" : df.format(model.semester2Average)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// PROPOSED grade
|
||||
if (model.semester2Proposed != null) {
|
||||
holder.gradesSubjectSemester2Proposed.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester2Proposed.setText(model.semester2Proposed.name);
|
||||
holder.gradesSubjectSemester2Proposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Proposed.name), PorterDuff.Mode.MULTIPLY));
|
||||
holder.gradesSubjectSemester2Proposed.setTextColor(Colors.gradeNameToColor(model.semester2Proposed.name));
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewProposed.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewProposed.setText(model.semester2Proposed.name);
|
||||
holder.gradesSubjectPreviewProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Proposed.name), PorterDuff.Mode.MULTIPLY));
|
||||
holder.gradesSubjectPreviewProposed.setTextColor(Colors.gradeNameToColor(model.semester2Proposed.name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester2Proposed.setVisibility(View.GONE);
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewProposed.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
// FINAL grade
|
||||
if (model.semester2Final != null) {
|
||||
holder.gradesSubjectSemester2Final.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester2Final.setText(model.semester2Final.name);
|
||||
holder.gradesSubjectSemester2Final.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Final.name), PorterDuff.Mode.MULTIPLY));
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewFinal.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewFinal.setText(model.semester2Final.name);
|
||||
holder.gradesSubjectPreviewFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Final.name), PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester2Final.setVisibility(View.GONE);
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewFinal.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (model.isDescriptiveSubject && !model.isNormalSubject && !model.isPointSubject && !model.isBehaviourSubject) {
|
||||
holder.gradesSubjectYearAverage.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectYearAverage.setVisibility(View.VISIBLE);
|
||||
// AVERAGE value
|
||||
int format = (model.isPointSubject ? R.string.grades_year_average_percent_format : model.isBehaviourSubject ? R.string.grades_year_average_point_format : R.string.grades_year_average_format);
|
||||
holder.gradesSubjectYearAverage.setText(
|
||||
getContext().getString(
|
||||
format,
|
||||
invalidAvg(model.yearAverage) ? "-" : df.format(model.yearAverage)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// PROPOSED grade
|
||||
if (model.yearProposed != null) {
|
||||
holder.gradesSubjectYearProposed.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectYearProposed.setText(model.yearProposed.name);
|
||||
holder.gradesSubjectYearProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearProposed.name), PorterDuff.Mode.MULTIPLY));
|
||||
holder.gradesSubjectYearProposed.setTextColor(Colors.gradeNameToColor(model.yearProposed.name));
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewYearProposed.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewYearProposed.setText(model.yearProposed.name);
|
||||
holder.gradesSubjectPreviewYearProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearProposed.name), PorterDuff.Mode.MULTIPLY));
|
||||
holder.gradesSubjectPreviewYearProposed.setTextColor(Colors.gradeNameToColor(model.yearProposed.name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectYearProposed.setVisibility(View.GONE);
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewYearProposed.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
// FINAL grade
|
||||
if (model.yearFinal != null) {
|
||||
holder.gradesSubjectYearFinal.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectYearFinal.setText(model.yearFinal.name);
|
||||
holder.gradesSubjectYearFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearFinal.name), PorterDuff.Mode.MULTIPLY));
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewYearFinal.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectPreviewYearFinal.setText(model.yearFinal.name);
|
||||
holder.gradesSubjectPreviewYearFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearFinal.name), PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectYearFinal.setVisibility(View.GONE);
|
||||
if (showSemester == 2) {
|
||||
holder.gradesSubjectPreviewYearFinal.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester2Header.setVisibility(View.GONE);
|
||||
holder.gradesSubjectSemester2Container.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// decrease the width by average, proposed, final and semester TextViews
|
||||
holder.gradesSubjectPreviewContainer.measure(WRAP_CONTENT, MATCH_PARENT);
|
||||
//Log.d(TAG, "gradesSubjectPreviewContainer "+holder.gradesSubjectPreviewContainer.getMeasuredWidth());
|
||||
|
||||
/*holder.gradesSubjectPreviewAverage.measure(WRAP_CONTENT, WRAP_CONTENT);
|
||||
maxWidthPx -= holder.gradesSubjectPreviewAverage.getMeasuredWidth();
|
||||
maxWidthPx -= 2*_5dp;
|
||||
if (holder.gradesSubjectPreviewProposed.getVisibility() == View.VISIBLE) {
|
||||
holder.gradesSubjectPreviewProposed.measure(WRAP_CONTENT, WRAP_CONTENT);
|
||||
maxWidthPx -= holder.gradesSubjectPreviewProposed.getMeasuredWidth();
|
||||
maxWidthPx -= _5dp;
|
||||
}
|
||||
if (holder.gradesSubjectPreviewFinal.getVisibility() == View.VISIBLE) {
|
||||
holder.gradesSubjectPreviewFinal.measure(WRAP_CONTENT, WRAP_CONTENT);
|
||||
maxWidthPx -= holder.gradesSubjectPreviewFinal.getMeasuredWidth();
|
||||
maxWidthPx -= _5dp;
|
||||
}*/
|
||||
maxWidthPx -= holder.gradesSubjectPreviewContainer.getMeasuredWidth();
|
||||
maxWidthPx -= _5dp;
|
||||
|
||||
for (GradeFull grade: gradeList) {
|
||||
if (grade.semester != showSemester)
|
||||
continue;
|
||||
|
||||
int gradeColor;
|
||||
if (model.profile.getGradeColorMode() == COLOR_MODE_DEFAULT) {
|
||||
gradeColor = grade.color;
|
||||
} else {
|
||||
gradeColor = Colors.gradeToColor(grade);
|
||||
}
|
||||
|
||||
TextView gradeName = new TextView(activity);
|
||||
gradeName.setText(grade.name);
|
||||
gradeName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.25 ? 0xff000000 : 0xffffffff);
|
||||
gradeName.setPadding(_5dp, 0, _5dp, 0);
|
||||
gradeName.setBackgroundResource(R.drawable.bg_rounded_4dp);
|
||||
gradeName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY));
|
||||
gradeName.setTypeface(null, Typeface.BOLD);
|
||||
|
||||
gradeName.measure(WRAP_CONTENT, WRAP_CONTENT);
|
||||
totalWidthPx += gradeName.getMeasuredWidth() + _5dp;
|
||||
//Log.d(TAG, "totalWidthPx " + totalWidthPx);
|
||||
if (totalWidthPx >= maxWidthPx) {
|
||||
if (ellipsized)
|
||||
continue;
|
||||
ellipsized = true;
|
||||
TextView ellipsisText = new TextView(activity);
|
||||
ellipsisText.setText(R.string.ellipsis);
|
||||
ellipsisText.setTextAppearance(activity, R.style.NavView_TextView);
|
||||
ellipsisText.setTypeface(null, Typeface.BOLD);
|
||||
ellipsisText.setPadding(0, 0, 0, 0);
|
||||
holder.gradesSubjectPreviewContent.addView(ellipsisText, layoutParams);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectPreviewContent.addView(gradeName, layoutParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (findViews) {
|
||||
//Log.d("GradesSubjectAdapter", "runOnUiThread");
|
||||
//this.viewHolder.gradesSubjectContent.setTag(View.VISIBLE);
|
||||
//this.viewHolder.gradesSubjectPreviewContainer.setTag(View.VISIBLE);
|
||||
activity.runOnUiThread(() -> {
|
||||
|
||||
holder.gradesSubjectRoot.setOnClickListener(v -> {
|
||||
if (holder.gradesSubjectContent.getVisibility() == View.GONE) {
|
||||
expandSubject(holder, model);
|
||||
}
|
||||
else {
|
||||
collapseSubject(holder, model);
|
||||
}
|
||||
});
|
||||
|
||||
holder.gradesSubjectSemester1Header.setOnClickListener(v -> {
|
||||
if (holder.gradesSubjectSemester1Container.getVisibility() == View.GONE) {
|
||||
if (gradesSetAsRead(holder, model, 1)) updateBadges(getContext(), model);
|
||||
|
||||
Anim.expand(holder.gradesSubjectSemester1Container, 500, null);
|
||||
if (holder.gradesSubjectSemester2Container.getVisibility() != View.GONE) {
|
||||
Anim.collapse(holder.gradesSubjectSemester2Container, 500, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Anim.collapse(holder.gradesSubjectSemester1Container, 500, null);
|
||||
}
|
||||
});
|
||||
holder.gradesSubjectSemester2Header.setOnClickListener(v -> {
|
||||
if (holder.gradesSubjectSemester2Container.getVisibility() == View.GONE) {
|
||||
if (gradesSetAsRead(holder, model, 2)) updateBadges(getContext(), model);
|
||||
|
||||
Anim.expand(holder.gradesSubjectSemester2Container, 500, null);
|
||||
if (holder.gradesSubjectSemester1Container.getVisibility() != View.GONE) {
|
||||
Anim.collapse(holder.gradesSubjectSemester1Container, 500, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Anim.collapse(holder.gradesSubjectSemester2Container, 500, null);
|
||||
}
|
||||
});
|
||||
|
||||
// hide the grade simulator when there are point, behaviour or descriptive grades
|
||||
if (model.isPointSubject || model.isBehaviourSubject || (model.isDescriptiveSubject && !model.isNormalSubject)) {
|
||||
holder.gradesSubjectSemester1EditButton.setVisibility(View.GONE);
|
||||
holder.gradesSubjectSemester2EditButton.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
holder.gradesSubjectSemester1EditButton.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester1EditButton.setOnClickListener(v -> {
|
||||
Bundle arguments = new Bundle();
|
||||
|
||||
if (model.subject != null) {
|
||||
arguments.putLong("subjectId", model.subject.id);
|
||||
}
|
||||
arguments.putInt("semester", 1);
|
||||
//d(TAG, "Model is " + model);
|
||||
switch (model.profile.getYearAverageMode()) {
|
||||
case YEAR_1_SEM_2_AVG:
|
||||
case YEAR_1_SEM_2_SEM:
|
||||
arguments.putInt("averageMode", -1);
|
||||
break;
|
||||
default:
|
||||
arguments.putInt("averageMode", model.semester2Final == null && model.profile.getYearAverageMode() == YEAR_1_AVG_2_SEM ? -1 : model.profile.getYearAverageMode());
|
||||
arguments.putFloat("yearAverageBefore", model.yearAverage);
|
||||
arguments.putFloat("gradeSumOtherSemester", model.gradeSumSemester2);
|
||||
arguments.putFloat("gradeCountOtherSemester", model.gradeCountSemester2);
|
||||
arguments.putFloat("averageOtherSemester", model.semester2Average);
|
||||
arguments.putFloat("finalOtherSemester", model.semester2Final == null ? -1 : model.semester2Final.value);
|
||||
break;
|
||||
}
|
||||
|
||||
activity.loadTarget(TARGET_GRADES_EDITOR, arguments);
|
||||
});
|
||||
holder.gradesSubjectSemester2EditButton.setVisibility(View.VISIBLE);
|
||||
holder.gradesSubjectSemester2EditButton.setOnClickListener(v -> {
|
||||
Bundle arguments = new Bundle();
|
||||
|
||||
if (model.subject != null) {
|
||||
arguments.putLong("subjectId", model.subject.id);
|
||||
}
|
||||
arguments.putInt("semester", 2);
|
||||
//d(TAG, "Model is " + model);
|
||||
switch (model.profile.getYearAverageMode()) {
|
||||
case YEAR_1_AVG_2_SEM:
|
||||
case YEAR_1_SEM_2_SEM:
|
||||
arguments.putInt("averageMode", -1);
|
||||
break;
|
||||
default:
|
||||
arguments.putInt("averageMode", model.semester1Final == null && model.profile.getYearAverageMode() == YEAR_1_SEM_2_AVG ? -1 : model.profile.getYearAverageMode());
|
||||
arguments.putFloat("yearAverageBefore", model.yearAverage);
|
||||
arguments.putFloat("gradeSumOtherSemester", model.gradeSumSemester1);
|
||||
arguments.putFloat("gradeCountOtherSemester", model.gradeCountSemester1);
|
||||
arguments.putFloat("averageOtherSemester", model.semester1Average);
|
||||
arguments.putFloat("finalOtherSemester", model.semester1Final == null ? -1 : model.semester1Final.value);
|
||||
break;
|
||||
}
|
||||
|
||||
activity.loadTarget(TARGET_GRADES_EDITOR, arguments);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
if (model != null && model.subject != null) {
|
||||
holder.lastSubject = model.subject.id;
|
||||
}
|
||||
super.onPostExecute(aVoid);
|
||||
}
|
||||
}
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public GradesSubjectAdapter(List<ItemGradesSubjectModel> data, MainActivity context) {
|
||||
super(context, R.layout.row_grades_subject_item, data);
|
||||
this.activity = context;
|
||||
this.subjectList = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = (Integer) v.getTag();
|
||||
Object object = getItem(position);
|
||||
ItemGradesSubjectModel dataModel = (ItemGradesSubjectModel)object;
|
||||
|
||||
}
|
||||
|
||||
private void findViews(ViewHolder holder, View root) {
|
||||
//holder.gradesSubjectRoot = root.findViewById(R.id.gradesSubjectRoot);
|
||||
holder.gradesSubjectTitle = root.findViewById(R.id.gradesSubjectTitle);
|
||||
holder.gradesSubjectExpandIndicator = root.findViewById(R.id.gradesSubjectExpandIndicator);
|
||||
|
||||
holder.gradesSubjectPreviewContainer = root.findViewById(R.id.gradesSubjectPreviewContainer);
|
||||
holder.gradesSubjectPreviewSemester = root.findViewById(R.id.gradesSubjectPreviewSemester);
|
||||
holder.gradesSubjectPreviewContent = root.findViewById(R.id.gradesSubjectPreviewContent);
|
||||
holder.gradesSubjectPreviewAverage = root.findViewById(R.id.gradesSubjectPreviewAverage);
|
||||
holder.gradesSubjectPreviewProposed = root.findViewById(R.id.gradesSubjectPreviewProposed);
|
||||
holder.gradesSubjectPreviewFinal = root.findViewById(R.id.gradesSubjectPreviewFinal);
|
||||
holder.gradesSubjectPreviewYearAverage = root.findViewById(R.id.gradesSubjectPreviewYearAverage);
|
||||
holder.gradesSubjectPreviewYearProposed = root.findViewById(R.id.gradesSubjectPreviewYearProposed);
|
||||
holder.gradesSubjectPreviewYearFinal = root.findViewById(R.id.gradesSubjectPreviewYearFinal);
|
||||
|
||||
holder.gradesSubjectContent = root.findViewById(R.id.gradesSubjectContent);
|
||||
|
||||
holder.gradesSubjectSemester1Header = root.findViewById(R.id.gradesSubjectSemester1Header);
|
||||
holder.gradesSubjectSemester1Title = root.findViewById(R.id.gradesSubjectSemester1Title);
|
||||
holder.gradesSubjectSemester1ExpandIndicator = root.findViewById(R.id.gradesSubjectSemester1ExpandIndicator);
|
||||
holder.gradesSubjectSemester1Average = root.findViewById(R.id.gradesSubjectSemester1Average);
|
||||
holder.gradesSubjectSemester1Proposed = root.findViewById(R.id.gradesSubjectSemester1Proposed);
|
||||
holder.gradesSubjectSemester1Final = root.findViewById(R.id.gradesSubjectSemester1Final);
|
||||
holder.gradesSubjectSemester1EditButton = root.findViewById(R.id.gradesSubjectSemester1EditButton);
|
||||
holder.gradesSubjectSemester1Container = root.findViewById(R.id.gradesSubjectSemester1Container);
|
||||
holder.gradesSubjectSemester1Nest = root.findViewById(R.id.gradesSubjectSemester1Nest);
|
||||
holder.gradesSubjectSemester1Content = root.findViewById(R.id.gradesSubjectSemester1Content);
|
||||
|
||||
holder.gradesSubjectSemester2Header = root.findViewById(R.id.gradesSubjectSemester2Header);
|
||||
holder.gradesSubjectSemester2Title = root.findViewById(R.id.gradesSubjectSemester2Title);
|
||||
holder.gradesSubjectSemester2ExpandIndicator = root.findViewById(R.id.gradesSubjectSemester2ExpandIndicator);
|
||||
holder.gradesSubjectSemester2Average = root.findViewById(R.id.gradesSubjectSemester2Average);
|
||||
holder.gradesSubjectSemester2Proposed = root.findViewById(R.id.gradesSubjectSemester2Proposed);
|
||||
holder.gradesSubjectSemester2Final = root.findViewById(R.id.gradesSubjectSemester2Final);
|
||||
holder.gradesSubjectSemester2EditButton = root.findViewById(R.id.gradesSubjectSemester2EditButton);
|
||||
holder.gradesSubjectSemester2Container = root.findViewById(R.id.gradesSubjectSemester2Container);
|
||||
holder.gradesSubjectSemester2Nest = root.findViewById(R.id.gradesSubjectSemester2Nest);
|
||||
holder.gradesSubjectSemester2Content = root.findViewById(R.id.gradesSubjectSemester2Content);
|
||||
|
||||
holder.gradesSubjectYearAverage = root.findViewById(R.id.gradesSubjectYearAverage);
|
||||
holder.gradesSubjectYearProposed = root.findViewById(R.id.gradesSubjectYearProposed);
|
||||
holder.gradesSubjectYearFinal = root.findViewById(R.id.gradesSubjectYearFinal);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
|
||||
ItemGradesSubjectModel model = subjectList.get(position);
|
||||
if (model == null) {
|
||||
//Toast.makeText(activity, "return convertView;", Toast.LENGTH_SHORT).show();
|
||||
return convertView;
|
||||
}
|
||||
ViewHolder holder;
|
||||
if (convertView == null) {
|
||||
try {
|
||||
convertView = LayoutInflater.from(activity).inflate(R.layout.row_grades_subject_item, parent, false);
|
||||
holder = new ViewHolder();
|
||||
holder.gradesSubjectRoot = convertView.findViewById(R.id.gradesSubjectRoot);
|
||||
convertView.setTag(holder);
|
||||
new BuildGradeViews(model, holder, parent, position, true).execute();
|
||||
return convertView;
|
||||
} catch (Exception e) {
|
||||
return new View(getContext());
|
||||
}
|
||||
}
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
Subject subject = model.subject;
|
||||
holder.gradesSubjectTitle.setText(subject != null ? subject.longName : "");
|
||||
/*if (model.getNotSeen() > 0) {
|
||||
viewHolder.notseen.setVisibility(0);
|
||||
viewHolder.notseen.setText(model.getNotSeen() + "");
|
||||
} else {
|
||||
viewHolder.notseen.setVisibility(8);
|
||||
}*/
|
||||
new BuildGradeViews(model, holder, parent, position, false).execute();
|
||||
return convertView;
|
||||
}
|
||||
|
||||
public int getViewTypeCount() {
|
||||
return getCount();
|
||||
}
|
||||
|
||||
public int getItemViewType(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
long lastSubject;
|
||||
|
||||
TextView gradesSubjectTitle;
|
||||
ConstraintLayout gradesSubjectRoot;
|
||||
IconicsImageView gradesSubjectExpandIndicator;
|
||||
|
||||
LinearLayout gradesSubjectPreviewContainer;
|
||||
TextView gradesSubjectPreviewSemester;
|
||||
LinearLayout gradesSubjectPreviewContent;
|
||||
TextView gradesSubjectPreviewAverage;
|
||||
TextView gradesSubjectPreviewProposed;
|
||||
TextView gradesSubjectPreviewFinal;
|
||||
TextView gradesSubjectPreviewYearAverage;
|
||||
TextView gradesSubjectPreviewYearProposed;
|
||||
TextView gradesSubjectPreviewYearFinal;
|
||||
|
||||
LinearLayout gradesSubjectContent;
|
||||
|
||||
LinearLayout gradesSubjectSemester1Header;
|
||||
TextView gradesSubjectSemester1Title;
|
||||
IconicsImageView gradesSubjectSemester1ExpandIndicator;
|
||||
TextView gradesSubjectSemester1Average;
|
||||
TextView gradesSubjectSemester1Proposed;
|
||||
TextView gradesSubjectSemester1Final;
|
||||
IconicsImageView gradesSubjectSemester1EditButton;
|
||||
LinearLayout gradesSubjectSemester1Container;
|
||||
NestedScrollView gradesSubjectSemester1Nest;
|
||||
RecyclerView gradesSubjectSemester1Content;
|
||||
|
||||
LinearLayout gradesSubjectSemester2Header;
|
||||
TextView gradesSubjectSemester2Title;
|
||||
IconicsImageView gradesSubjectSemester2ExpandIndicator;
|
||||
TextView gradesSubjectSemester2Average;
|
||||
TextView gradesSubjectSemester2Proposed;
|
||||
TextView gradesSubjectSemester2Final;
|
||||
IconicsImageView gradesSubjectSemester2EditButton;
|
||||
LinearLayout gradesSubjectSemester2Container;
|
||||
NestedScrollView gradesSubjectSemester2Nest;
|
||||
RecyclerView gradesSubjectSemester2Content;
|
||||
|
||||
TextView gradesSubjectYearAverage;
|
||||
TextView gradesSubjectYearProposed;
|
||||
TextView gradesSubjectYearFinal;
|
||||
}
|
||||
}
|
@ -0,0 +1,566 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.grades;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterGradesBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Grade;
|
||||
import pl.szczodrzynski.edziennik.datamodels.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Subject;
|
||||
import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Metadata.TYPE_GRADE;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_AVG_2_AVG;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_AVG_2_SEM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_SEM_2_AVG;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_1_SEM_2_SEM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.YEAR_ALL_GRADES;
|
||||
import static pl.szczodrzynski.edziennik.utils.models.AppConfig.ORDER_BY_DATE_ASC;
|
||||
import static pl.szczodrzynski.edziennik.utils.models.AppConfig.ORDER_BY_DATE_DESC;
|
||||
import static pl.szczodrzynski.edziennik.utils.models.AppConfig.ORDER_BY_SUBJECT_ASC;
|
||||
|
||||
public class RegisterGradesFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterGradesBinding b = 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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_grades, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
b.refreshLayout.setNestedScrollingEnabled(true);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
ListView listView;
|
||||
List<ItemGradesSubjectModel> subjectList;
|
||||
|
||||
private boolean sortModeChanged = false;
|
||||
|
||||
private String getRegisterCardAverageModeSubText() {
|
||||
switch (app.profile.getYearAverageMode()) {
|
||||
default:
|
||||
case YEAR_1_AVG_2_AVG:
|
||||
return getString(R.string.settings_register_avg_mode_0_short);
|
||||
case YEAR_1_SEM_2_AVG:
|
||||
return getString(R.string.settings_register_avg_mode_1_short);
|
||||
case YEAR_1_AVG_2_SEM:
|
||||
return getString(R.string.settings_register_avg_mode_2_short);
|
||||
case YEAR_1_SEM_2_SEM:
|
||||
return getString(R.string.settings_register_avg_mode_3_short);
|
||||
case YEAR_ALL_GRADES:
|
||||
return getString(R.string.settings_register_avg_mode_4_short);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
/*activity.getBottomSheet().setToggleGroupEnabled(true);
|
||||
activity.getBottomSheet().toggleGroupRemoveItems();
|
||||
activity.getBottomSheet().setToggleGroupSelectionMode(NavBottomSheet.TOGGLE_GROUP_SORTING_ORDER);
|
||||
activity.getBottomSheet().toggleGroupAddItem(0, getString(R.string.sort_by_date), (Drawable)null, SORT_MODE_DESCENDING);
|
||||
activity.getBottomSheet().toggleGroupAddItem(1, getString(R.string.sort_by_subject), (Drawable)null, SORT_MODE_ASCENDING);
|
||||
activity.getBottomSheet().setToggleGroupSortingOrderListener((id, sortMode) -> {
|
||||
sortModeChanged = true;
|
||||
if (id == 0 && sortMode == SORT_MODE_ASCENDING) {
|
||||
app.appConfig.gradesOrderBy = ORDER_BY_DATE_ASC;
|
||||
}
|
||||
else if (id == 1 && sortMode == SORT_MODE_ASCENDING) {
|
||||
app.appConfig.gradesOrderBy = ORDER_BY_SUBJECT_ASC;
|
||||
}
|
||||
else if (id == 0 && sortMode == SORT_MODE_DESCENDING) {
|
||||
app.appConfig.gradesOrderBy = ORDER_BY_DATE_DESC;
|
||||
}
|
||||
else if (id == 1 && sortMode == SORT_MODE_DESCENDING) {
|
||||
app.appConfig.gradesOrderBy = ORDER_BY_SUBJECT_DESC;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
activity.getBottomSheet().setToggleGroupTitle("Sortowanie");
|
||||
activity.getBottomSheet().toggleGroupCheck(0);
|
||||
activity.getBottomSheet().setOnCloseListener(() -> {
|
||||
if (sortModeChanged) {
|
||||
sortModeChanged = false;
|
||||
activity.reloadTarget();
|
||||
}
|
||||
return null;
|
||||
});*/
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_grades_averages)
|
||||
.withDescription(R.string.menu_grades_averages_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_chart_line)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
showAverages();
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_grades_color_mode)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_palette)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.dialog_grades_color_mode_title)
|
||||
.items(R.array.dialog_grades_color_modes)
|
||||
.itemsCallbackSingleChoice(app.profile.getGradeColorMode(), (dialog, view1, which, text) -> {
|
||||
app.profile.setGradeColorMode(which);
|
||||
app.profileSaveAsync();
|
||||
activity.reloadTarget();
|
||||
return true;
|
||||
})
|
||||
.show();
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_grades_sort_mode)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_sort)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.dialog_grades_sort_title)
|
||||
.items(R.array.dialog_grades_sort_modes)
|
||||
.itemsCallbackSingleChoice(app.appConfig.gradesOrderBy, (dialog, view1, which, text) -> {
|
||||
app.appConfig.gradesOrderBy = which;
|
||||
app.saveConfig("gradesOrderBy");
|
||||
activity.reloadTarget();
|
||||
return true;
|
||||
})
|
||||
.show();
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_grades_average_mode)
|
||||
.withDescription(getRegisterCardAverageModeSubText())
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_scale_balance)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
List<CharSequence> modeNames = new ArrayList<>();
|
||||
modeNames.add(getString(R.string.settings_register_avg_mode_4));
|
||||
modeNames.add(getString(R.string.settings_register_avg_mode_0));
|
||||
modeNames.add(getString(R.string.settings_register_avg_mode_1));
|
||||
modeNames.add(getString(R.string.settings_register_avg_mode_2));
|
||||
modeNames.add(getString(R.string.settings_register_avg_mode_3));
|
||||
List<Integer> modeIds = new ArrayList<>();
|
||||
modeIds.add(YEAR_ALL_GRADES);
|
||||
modeIds.add(YEAR_1_AVG_2_AVG);
|
||||
modeIds.add(YEAR_1_SEM_2_AVG);
|
||||
modeIds.add(YEAR_1_AVG_2_SEM);
|
||||
modeIds.add(YEAR_1_SEM_2_SEM);
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(getString(R.string.settings_register_avg_mode_dialog_title))
|
||||
.content(getString(R.string.settings_register_avg_mode_dialog_text))
|
||||
.items(modeNames)
|
||||
.itemsCallbackSingleChoice(modeIds.indexOf(app.profile.getYearAverageMode()), (dialog, itemView, which, text) -> {
|
||||
app.profile.setYearAverageMode(modeIds.get(which));
|
||||
app.profileSaveAsync();
|
||||
activity.reloadTarget();
|
||||
return true;
|
||||
})
|
||||
.show();
|
||||
}),
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_GRADE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
activity.gainAttention();
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_GRADES, b.refreshLayout);
|
||||
});*/
|
||||
|
||||
listView = b.gradesRecyclerView;
|
||||
//listView.setHasFixedSize(true);
|
||||
//listView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
long expandSubjectId = -1;
|
||||
if (getArguments() != null) {
|
||||
expandSubjectId = getArguments().getLong("gradesSubjectId", -1);
|
||||
}
|
||||
|
||||
/*b.gradesSwipeLayout.setOnRefreshListener(() -> {
|
||||
Toast.makeText(activity, "Works!", Toast.LENGTH_LONG).show();
|
||||
// To keep animation for 4 seconds
|
||||
new Handler().postDelayed(() -> {
|
||||
// Stop animation (This will be after 3 seconds)
|
||||
b.gradesSwipeLayout.setRefreshing(false);
|
||||
}, 3000);
|
||||
});*/
|
||||
|
||||
long finalExpandSubjectId = expandSubjectId;
|
||||
String orderBy;
|
||||
if (app.appConfig.gradesOrderBy == ORDER_BY_SUBJECT_ASC) {
|
||||
orderBy = "subjectLongName ASC, addedDate DESC";
|
||||
}
|
||||
else if (app.appConfig.gradesOrderBy == ORDER_BY_DATE_DESC) {
|
||||
orderBy = "addedDate DESC";
|
||||
}
|
||||
else if (app.appConfig.gradesOrderBy == ORDER_BY_DATE_ASC) {
|
||||
orderBy = "addedDate ASC";
|
||||
}
|
||||
else {
|
||||
orderBy = "subjectLongName DESC, addedDate DESC";
|
||||
}
|
||||
|
||||
app.db.gradeDao().getAllOrderBy(App.profileId, orderBy).observe(this, grades -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
subjectList = new ArrayList<>();
|
||||
|
||||
// now we have all grades from the newest to the oldest
|
||||
for (GradeFull grade: grades) {
|
||||
ItemGradesSubjectModel model = ItemGradesSubjectModel.searchModelBySubjectId(subjectList, grade.subjectId);
|
||||
if (model == null) {
|
||||
model = new ItemGradesSubjectModel(app.profile, new Subject(App.profileId, grade.subjectId, grade.subjectLongName, grade.subjectShortName), new ArrayList<>(), new ArrayList<>());//ItemGradesSubjectModel.searchModelBySubjectId(subjectList, grade.subjectId);
|
||||
subjectList.add(model);
|
||||
if (model.subject != null && model.subject.id == finalExpandSubjectId) {
|
||||
model.expandView = true;
|
||||
}
|
||||
}
|
||||
if (!grade.seen && grade.semester == 1) {
|
||||
model.semester1Unread++;
|
||||
}
|
||||
if (!grade.seen && grade.semester == 2) {
|
||||
model.semester2Unread++;
|
||||
}
|
||||
// COUNT POINT GRADES
|
||||
if (grade.type == Grade.TYPE_POINT) {
|
||||
model.isPointSubject = true;
|
||||
if (grade.semester == 1) {
|
||||
model.gradeSumOverall += grade.value;
|
||||
model.gradeCountOverall += grade.valueMax;
|
||||
model.gradeSumSemester1 += grade.value;
|
||||
model.gradeCountSemester1 += grade.valueMax;
|
||||
model.semester1Average = model.gradeSumSemester1 / model.gradeCountSemester1 * 100;
|
||||
model.grades1.add(grade);
|
||||
}
|
||||
if (grade.semester == 2) {
|
||||
model.gradeSumOverall += grade.value;
|
||||
model.gradeCountOverall += grade.valueMax;
|
||||
model.gradeSumSemester2 += grade.value;
|
||||
model.gradeCountSemester2 += grade.valueMax;
|
||||
model.semester2Average = model.gradeSumSemester2 / model.gradeCountSemester2 * 100;
|
||||
model.grades2.add(grade);
|
||||
}
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_BEHAVIOUR) {
|
||||
model.isBehaviourSubject = true;
|
||||
if (grade.semester == 1) {
|
||||
model.semester1Average += grade.value;
|
||||
model.yearAverage += grade.value;
|
||||
model.grades1.add(grade);
|
||||
}
|
||||
if (grade.semester == 2) {
|
||||
model.semester2Average += grade.value;
|
||||
model.yearAverage += grade.value;
|
||||
model.grades2.add(grade);
|
||||
}
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_NORMAL) {
|
||||
model.isNormalSubject = true;
|
||||
float weight = grade.weight;
|
||||
if (weight < 0) {
|
||||
// do not show *normal* grades with negative weight - these are historical grades - Iuczniowie
|
||||
continue;
|
||||
}
|
||||
if (app.appConfig.dontCountZeroToAverage && grade.name.equals("0")) {
|
||||
weight = 0;
|
||||
}
|
||||
float valueWeighted = grade.value * weight;
|
||||
if (grade.semester == 1) {
|
||||
model.gradeSumOverall += valueWeighted;
|
||||
model.gradeCountOverall += weight;
|
||||
model.gradeSumSemester1 += valueWeighted;
|
||||
model.gradeCountSemester1 += weight;
|
||||
model.semester1Average = model.gradeSumSemester1 / model.gradeCountSemester1;
|
||||
if (grade.parentId == -1) {
|
||||
// show only "current" grades - these which are not historical
|
||||
model.grades1.add(grade);
|
||||
}
|
||||
}
|
||||
if (grade.semester == 2) {
|
||||
model.gradeSumOverall += valueWeighted;
|
||||
model.gradeCountOverall += weight;
|
||||
model.gradeSumSemester2 += valueWeighted;
|
||||
model.gradeCountSemester2 += weight;
|
||||
model.semester2Average = model.gradeSumSemester2 / model.gradeCountSemester2;
|
||||
if (grade.parentId == -1) {
|
||||
// show only "current" grades - these which are not historical
|
||||
model.grades2.add(grade);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_SEMESTER1_PROPOSED) {
|
||||
model.semester1Proposed = grade;
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_SEMESTER1_FINAL) {
|
||||
model.semester1Final = grade;
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_SEMESTER2_PROPOSED) {
|
||||
model.semester2Proposed = grade;
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_SEMESTER2_FINAL) {
|
||||
model.semester2Final = grade;
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_YEAR_PROPOSED) {
|
||||
model.yearProposed = grade;
|
||||
}
|
||||
else if (grade.type == Grade.TYPE_YEAR_FINAL) {
|
||||
model.yearFinal = grade;
|
||||
}
|
||||
else {
|
||||
// descriptive grades, text grades
|
||||
model.isDescriptiveSubject = true;
|
||||
if (grade.semester == 1) {
|
||||
model.grades1.add(grade);
|
||||
}
|
||||
if (grade.semester == 2) {
|
||||
model.grades2.add(grade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ItemGradesSubjectModel model: subjectList) {
|
||||
if (model.isPointSubject) {
|
||||
model.yearAverage = model.gradeSumOverall / model.gradeCountOverall * 100.0f; // map the point grade "average" % value from 0.0f-1.0f to 0%-100%
|
||||
}
|
||||
/*else if (model.isDescriptiveSubject && !model.isNormalSubject) {
|
||||
// applies for only descriptive grades - do nothing. average is hidden
|
||||
//model.isDescriptiveSubject = false;
|
||||
//model.semester1Average = -1;
|
||||
//model.semester2Average = -1;
|
||||
//model.yearAverage = -1;
|
||||
}*/
|
||||
else if (!model.isBehaviourSubject && model.isNormalSubject) {
|
||||
// applies for normal grades & normal+descriptive grades
|
||||
// calculate the normal grade average based on the user's setting
|
||||
switch (app.profile.getYearAverageMode()) {
|
||||
case YEAR_1_AVG_2_AVG:
|
||||
model.yearAverage = (model.semester1Average + model.semester2Average) / 2;
|
||||
break;
|
||||
case YEAR_1_SEM_2_AVG:
|
||||
model.yearAverage = model.semester1Final != null ? (model.semester1Final.value + model.semester2Average) / 2 : 0.0f;
|
||||
break;
|
||||
case YEAR_1_AVG_2_SEM:
|
||||
model.yearAverage = model.semester2Final != null ? (model.semester1Average + model.semester2Final.value) / 2 : 0.0f;
|
||||
break;
|
||||
case YEAR_1_SEM_2_SEM:
|
||||
model.yearAverage = model.semester1Final != null && model.semester2Final != null ? (model.semester1Final.value + model.semester2Final.value) / 2 : 0.0f;
|
||||
break;
|
||||
default:
|
||||
case YEAR_ALL_GRADES:
|
||||
model.yearAverage = model.gradeSumOverall / model.gradeCountOverall;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subjectList.size() > 0) {
|
||||
GradesSubjectAdapter adapter;
|
||||
if ((adapter = (GradesSubjectAdapter) listView.getAdapter()) != null) {
|
||||
adapter.subjectList = subjectList;
|
||||
adapter.notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
adapter = new GradesSubjectAdapter(subjectList, activity);
|
||||
listView.setAdapter(adapter);
|
||||
listView.setVisibility(View.VISIBLE);
|
||||
b.gradesNoData.setVisibility(View.GONE);
|
||||
if (finalExpandSubjectId != -1) {
|
||||
int subjectIndex = subjectList.indexOf(ItemGradesSubjectModel.searchModelBySubjectId(subjectList, finalExpandSubjectId));
|
||||
listView.setSelection(subjectIndex > 0 ? subjectIndex - 1 : subjectIndex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
listView.setVisibility(View.GONE);
|
||||
b.gradesNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private int gradeFromAverage(float value) {
|
||||
int grade = (int)Math.floor(value);
|
||||
if (value % 1.0f >= 0.75f)
|
||||
grade++;
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void showAverages() {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded() || subjectList == null)
|
||||
return;
|
||||
|
||||
float semester1Sum = 0;
|
||||
float semester1Count = 0;
|
||||
float semester1ProposedSum = 0;
|
||||
float semester1ProposedCount = 0;
|
||||
float semester1FinalSum = 0;
|
||||
float semester1FinalCount = 0;
|
||||
|
||||
float semester2Sum = 0;
|
||||
float semester2Count = 0;
|
||||
float semester2ProposedSum = 0;
|
||||
float semester2ProposedCount = 0;
|
||||
float semester2FinalSum = 0;
|
||||
float semester2FinalCount = 0;
|
||||
|
||||
float yearSum = 0;
|
||||
float yearCount = 0;
|
||||
float yearProposedSum = 0;
|
||||
float yearProposedCount = 0;
|
||||
float yearFinalSum = 0;
|
||||
float yearFinalCount = 0;
|
||||
|
||||
for (ItemGradesSubjectModel subject: subjectList) {
|
||||
// we cannot skip non-normal subjects because a point subject may also have a final grade
|
||||
if (subject.isBehaviourSubject)
|
||||
continue;
|
||||
|
||||
// SEMESTER 1 GRADES & AVERAGES
|
||||
if (subject.semester1Final != null) { // if final available, add to final grades & expected grades
|
||||
semester1FinalSum += subject.semester1Final.value;
|
||||
semester1FinalCount++;
|
||||
semester1Sum += subject.semester1Final.value;
|
||||
semester1Count++;
|
||||
}
|
||||
else if (subject.semester1Proposed != null) { // if final not available, add proposed to expected grades
|
||||
semester1Sum += subject.semester1Proposed.value;
|
||||
semester1Count++;
|
||||
}
|
||||
else if (!Float.isNaN(subject.semester1Average)
|
||||
&& subject.semester1Average > 0
|
||||
&& !subject.isPointSubject) { // if final&proposed unavailable, calculate from avg
|
||||
semester1Sum += gradeFromAverage(subject.semester1Average);
|
||||
semester1Count++;
|
||||
}
|
||||
if (subject.semester1Proposed != null) { // add proposed to proposed grades even if final is available
|
||||
semester1ProposedSum += subject.semester1Proposed.value;
|
||||
semester1ProposedCount++;
|
||||
}
|
||||
|
||||
// SEMESTER 2 GRADES & AVERAGES
|
||||
if (subject.semester2Final != null) { // if final available, add to final grades & expected grades
|
||||
semester2FinalSum += subject.semester2Final.value;
|
||||
semester2FinalCount++;
|
||||
semester2Sum += subject.semester2Final.value;
|
||||
semester2Count++;
|
||||
}
|
||||
else if (subject.semester2Proposed != null) { // if final not available, add proposed to expected grades
|
||||
semester2Sum += subject.semester2Proposed.value;
|
||||
semester2Count++;
|
||||
}
|
||||
else if (!Float.isNaN(subject.semester2Average)
|
||||
&& subject.semester2Average > 0
|
||||
&& !subject.isPointSubject) { // if final&proposed unavailable, calculate from avg
|
||||
semester2Sum += gradeFromAverage(subject.semester2Average);
|
||||
semester2Count++;
|
||||
}
|
||||
if (subject.semester2Proposed != null) { // add proposed to proposed grades even if final is available
|
||||
semester2ProposedSum += subject.semester2Proposed.value;
|
||||
semester2ProposedCount++;
|
||||
}
|
||||
|
||||
// YEAR GRADES & AVERAGES
|
||||
if (subject.yearFinal != null) { // if final available, add to final grades & expected grades
|
||||
yearFinalSum += subject.yearFinal.value;
|
||||
yearFinalCount++;
|
||||
yearSum += subject.yearFinal.value;
|
||||
yearCount++;
|
||||
}
|
||||
else if (subject.yearProposed != null) { // if final not available, add proposed to expected grades
|
||||
yearSum += subject.yearProposed.value;
|
||||
yearCount++;
|
||||
}
|
||||
else if (!Float.isNaN(subject.yearAverage)
|
||||
&& subject.yearAverage > 0
|
||||
&& !subject.isPointSubject) { // if final&proposed unavailable, calculate from avg
|
||||
yearSum += gradeFromAverage(subject.yearAverage);
|
||||
yearCount++;
|
||||
}
|
||||
if (subject.yearProposed != null) { // add proposed to proposed grades even if final is available
|
||||
yearProposedSum += subject.yearProposed.value;
|
||||
yearProposedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
DecimalFormat df = new DecimalFormat("0.00");
|
||||
|
||||
String semester1ExpectedAverageStr = semester1Count > semester1ProposedCount || semester1Count > semester1FinalCount ? getString(R.string.dialog_averages_expected_format, 1, semester1Sum / semester1Count) : "";
|
||||
String semester1ProposedAverageStr = semester1ProposedCount > 0 ? getString(R.string.dialog_averages_proposed_format, 1, semester1ProposedSum / semester1ProposedCount) : "";
|
||||
String semester1FinalAverageStr = semester1FinalCount > 0 ? getString(R.string.dialog_averages_final_format, 1, semester1FinalSum / semester1FinalCount) : "";
|
||||
|
||||
String semester2ExpectedAverageStr = semester2Count > semester2ProposedCount || semester2Count > semester2FinalCount ? getString(R.string.dialog_averages_expected_format, 2, semester2Sum / semester2Count) : "";
|
||||
String semester2ProposedAverageStr = semester2ProposedCount > 0 ? getString(R.string.dialog_averages_proposed_format, 2, semester2ProposedSum / semester2ProposedCount) : "";
|
||||
String semester2FinalAverageStr = semester2FinalCount > 0 ? getString(R.string.dialog_averages_final_format, 2, semester2FinalSum / semester2FinalCount) : "";
|
||||
|
||||
String yearExpectedAverageStr = yearCount > yearProposedCount || yearCount > yearFinalCount ? getString(R.string.dialog_averages_expected_yearly_format, yearSum / yearCount) : "";
|
||||
String yearProposedAverageStr = yearProposedCount > 0 ? getString(R.string.dialog_averages_proposed_yearly_format, yearProposedSum / yearProposedCount) : "";
|
||||
String yearFinalAverageStr = yearFinalCount > 0 ? getString(R.string.dialog_averages_final_yearly_format, yearFinalSum / yearFinalCount) : "";
|
||||
|
||||
if (semester1ExpectedAverageStr.isEmpty() && semester1ProposedAverageStr.isEmpty() && semester1FinalAverageStr.isEmpty()) {
|
||||
semester1ExpectedAverageStr = getString(R.string.dialog_averages_unavailable_format, 1);
|
||||
}
|
||||
if (semester2ExpectedAverageStr.isEmpty() && semester2ProposedAverageStr.isEmpty() && semester2FinalAverageStr.isEmpty()) {
|
||||
semester2ExpectedAverageStr = getString(R.string.dialog_averages_unavailable_format, 2);
|
||||
}
|
||||
if (yearExpectedAverageStr.isEmpty() && yearProposedAverageStr.isEmpty() && yearFinalAverageStr.isEmpty()) {
|
||||
yearExpectedAverageStr = getString(R.string.dialog_averages_unavailable_yearly);
|
||||
}
|
||||
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.dialog_averages_title)
|
||||
.content(getString(
|
||||
R.string.dialog_averages_format,
|
||||
semester1ExpectedAverageStr,
|
||||
semester1ProposedAverageStr,
|
||||
semester1FinalAverageStr,
|
||||
semester2ExpectedAverageStr,
|
||||
semester2ProposedAverageStr,
|
||||
semester2FinalAverageStr,
|
||||
yearExpectedAverageStr,
|
||||
yearProposedAverageStr,
|
||||
yearFinalAverageStr))
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.grades.editor
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.Typeface
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.daimajia.swipe.SwipeLayout
|
||||
import com.mikepenz.iconics.view.IconicsImageView
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment.Companion.modifyGradeChooser
|
||||
import pl.szczodrzynski.edziennik.utils.Colors.gradeNameToColor
|
||||
import java.text.DecimalFormat
|
||||
|
||||
class GradesEditorAdapter(
|
||||
private val mContext: Context,
|
||||
private val gradeList: List<GradesEditorFragment.EditorGrade>,
|
||||
private val listener: OnGradeActionListener
|
||||
) : RecyclerView.Adapter<GradesEditorAdapter.ViewHolder>() {
|
||||
|
||||
interface OnGradeActionListener {
|
||||
fun onClickRemove(gradeId: Long)
|
||||
fun onClickEdit(gradeId: Long)
|
||||
fun onClickAdd()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
//inflating and returning our view holder
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val view = inflater.inflate(R.layout.row_grades_editor_item, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val app = mContext.applicationContext as App
|
||||
|
||||
val editorGrade = gradeList[position]
|
||||
|
||||
holder.gradesListRoot.setOnClickListener { holder.swipeLayout.toggle() }
|
||||
|
||||
val gradeColor = gradeNameToColor(editorGrade.name)
|
||||
|
||||
holder.gradesListName.text = editorGrade.name
|
||||
holder.gradesListName.isSelected = true
|
||||
holder.gradesListName.setTypeface(null, Typeface.BOLD)
|
||||
holder.gradesListName.setTextColor(if (ColorUtils.calculateLuminance(gradeColor) > 0.25) -0x1000000 else -0x1)
|
||||
holder.gradesListName.background.colorFilter = PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY)
|
||||
holder.gradesListCategory.text = editorGrade.category
|
||||
if (editorGrade.weight < 0) {
|
||||
editorGrade.weight *= -1f
|
||||
}
|
||||
|
||||
if (editorGrade.weight == 0f) {
|
||||
holder.gradesListWeight.text = app.getString(R.string.grades_weight_not_counted)
|
||||
} else {
|
||||
holder.gradesListWeight.text = app.getString(R.string.grades_weight_format, DecimalFormat("0.##").format(editorGrade.weight.toDouble()))
|
||||
}
|
||||
|
||||
holder.gradesListValue.text = mContext.getString(R.string.grades_value_format, DecimalFormat("0.00").format(editorGrade.value.toDouble()))
|
||||
|
||||
|
||||
holder.swipeLayout.showMode = SwipeLayout.ShowMode.LayDown
|
||||
holder.swipeLayout.addDrag(SwipeLayout.DragEdge.Right, holder.bottomWrapper)
|
||||
holder.swipeLayout.addSwipeListener(object : SwipeLayout.SwipeListener {
|
||||
override fun onClose(layout: SwipeLayout) {
|
||||
//when the SurfaceView totally cover the BottomView.
|
||||
}
|
||||
|
||||
override fun onUpdate(layout: SwipeLayout, leftOffset: Int, topOffset: Int) {
|
||||
//you are swiping.
|
||||
}
|
||||
|
||||
override fun onStartOpen(layout: SwipeLayout) {
|
||||
|
||||
}
|
||||
|
||||
override fun onOpen(layout: SwipeLayout) {
|
||||
//when the BottomView totally show.
|
||||
}
|
||||
|
||||
override fun onStartClose(layout: SwipeLayout) {
|
||||
|
||||
}
|
||||
|
||||
override fun onHandRelease(layout: SwipeLayout, xvel: Float, yvel: Float) {
|
||||
//when user's hand released.
|
||||
}
|
||||
})
|
||||
|
||||
holder.buttonRemove.setOnClickListener { listener.onClickRemove(editorGrade.id) }
|
||||
|
||||
holder.buttonEdit.setOnClickListener { v -> modifyGradeChooser(v, editorGrade) { listener.onClickEdit(editorGrade.id) } }
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return gradeList.size
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var gradesListRoot: ConstraintLayout = itemView.findViewById(R.id.gradesListRoot)
|
||||
var gradesListName: TextView = itemView.findViewById(R.id.gradesListName)
|
||||
var gradesListWeight: TextView = itemView.findViewById(R.id.gradesListWeight)
|
||||
var gradesListValue: TextView = itemView.findViewById(R.id.gradesListValue)
|
||||
var gradesListCategory: TextView = itemView.findViewById(R.id.gradesListCategory)
|
||||
var swipeLayout: SwipeLayout = itemView.findViewById(R.id.swipeLayout)
|
||||
var bottomWrapper: View = itemView.findViewById(R.id.bottom_wrapper)
|
||||
var buttonRemove: IconicsImageView = itemView.findViewById(R.id.buttonRemove)
|
||||
var buttonEdit: IconicsImageView = itemView.findViewById(R.id.buttonEdit)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,359 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.grades.editor
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentGradesEditorBinding
|
||||
import pl.szczodrzynski.edziennik.datamodels.Grade
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile.Companion.YEAR_1_AVG_2_AVG
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile.Companion.YEAR_1_AVG_2_SEM
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile.Companion.YEAR_1_SEM_2_AVG
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile.Companion.YEAR_ALL_GRADES
|
||||
import pl.szczodrzynski.edziennik.utils.Colors
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import kotlin.math.floor
|
||||
|
||||
class GradesEditorFragment : Fragment() {
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentGradesEditorBinding
|
||||
/*
|
||||
private val navController: NavController by lazy { Navigation.findNavController(b.root) }
|
||||
*/
|
||||
|
||||
private var subjectId: Long = -1
|
||||
private var semester: Int = 1
|
||||
|
||||
private val editorGrades = ArrayList<EditorGrade>()
|
||||
private lateinit var addingGrade: EditorGrade
|
||||
|
||||
private var gradeSumSemester = 0f
|
||||
private var gradeCountSemester = 0f
|
||||
private var averageSemester = 0f
|
||||
|
||||
private var gradeSumOtherSemester = 0f
|
||||
private var gradeCountOtherSemester = 0f
|
||||
private var averageOtherSemester = 0f
|
||||
|
||||
private var finalOtherSemester = 0.0f
|
||||
|
||||
private var averageMode = YEAR_ALL_GRADES // this means the container should be gone
|
||||
private var yearAverageBefore = 0.0f
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = FragmentGradesEditorBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
subjectId = arguments.getLong("subjectId", -1)
|
||||
semester = arguments.getInt("semester", 1)
|
||||
|
||||
if (subjectId == -1L) {
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.error_occured)
|
||||
.content(R.string.error_no_subject_id)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive { _, _ -> activity.navigateUp() }
|
||||
.show()
|
||||
return
|
||||
}
|
||||
|
||||
averageMode = arguments.getInt("averageMode", YEAR_ALL_GRADES)
|
||||
yearAverageBefore = arguments.getFloat("yearAverageBefore", -1f)
|
||||
|
||||
gradeSumOtherSemester = arguments.getFloat("gradeSumOtherSemester", -1f)
|
||||
gradeCountOtherSemester = arguments.getFloat("gradeCountOtherSemester", -1f)
|
||||
averageOtherSemester = arguments.getFloat("averageOtherSemester", -1f)
|
||||
finalOtherSemester = arguments.getFloat("finalOtherSemester", -1f)
|
||||
|
||||
b.listView.setHasFixedSize(false)
|
||||
b.listView.isNestedScrollingEnabled = false
|
||||
b.listView.layoutManager = LinearLayoutManager(context)
|
||||
b.listView.adapter = GradesEditorAdapter(context!!, editorGrades, object : GradesEditorAdapter.OnGradeActionListener {
|
||||
override fun onClickRemove(gradeId: Long) {
|
||||
gradeSumSemester = 0f
|
||||
gradeCountSemester = 0f
|
||||
averageSemester = 0f
|
||||
var pos = 0
|
||||
var removePos = 0
|
||||
for (editorGrade in editorGrades) {
|
||||
if (editorGrade.id == gradeId) {
|
||||
removePos = pos
|
||||
pos++
|
||||
continue
|
||||
}
|
||||
var weight = editorGrade.weight
|
||||
if (app.appConfig.dontCountZeroToAverage && editorGrade.name == "0") {
|
||||
weight = 0f
|
||||
}
|
||||
val value = editorGrade.value * weight
|
||||
gradeSumSemester += value
|
||||
gradeCountSemester += weight//(value > 0 ? weight : 0);
|
||||
pos++
|
||||
}
|
||||
editorGrades.removeAt(removePos)
|
||||
averageSemester = gradeSumSemester / gradeCountSemester
|
||||
refreshYearAverageAfter()
|
||||
b.averageAfter.text = String.format(Locale.getDefault(), "%.02f", averageSemester)
|
||||
var gradeInt = floor(averageSemester.toDouble()).toInt()
|
||||
if (averageSemester % 1 >= 0.75)
|
||||
gradeInt++
|
||||
b.averageAfter.background.colorFilter = PorterDuffColorFilter(Colors.gradeNameToColor(gradeInt.toString()), PorterDuff.Mode.MULTIPLY)
|
||||
b.listView.adapter!!.notifyItemRemoved(removePos)
|
||||
}
|
||||
|
||||
override fun onClickEdit(gradeId: Long) {
|
||||
refreshDataset()
|
||||
}
|
||||
|
||||
override fun onClickAdd() {
|
||||
|
||||
}
|
||||
})
|
||||
b.listView.visibility = View.VISIBLE
|
||||
|
||||
b.restoreGrades.setOnClickListener { refreshViews() }
|
||||
|
||||
b.addGrade.setOnClickListener { v ->
|
||||
addingGrade = EditorGrade(System.currentTimeMillis(), "0", 0.0f, getString(R.string.grades_editor_new_grade), 0f)
|
||||
addGradeHandler(v, addingGrade) {
|
||||
editorGrades.add(0, addingGrade)
|
||||
refreshDataset()
|
||||
}
|
||||
}
|
||||
|
||||
refreshViews()
|
||||
}
|
||||
|
||||
private fun refreshYearAverageAfter() {
|
||||
val yearAverage = when (averageMode) {
|
||||
YEAR_ALL_GRADES -> (gradeSumOtherSemester + gradeSumSemester) / (gradeCountOtherSemester + gradeCountSemester)
|
||||
YEAR_1_AVG_2_AVG -> (averageOtherSemester + averageSemester) / 2
|
||||
YEAR_1_SEM_2_AVG, // the final grade is always the 'other'
|
||||
YEAR_1_AVG_2_SEM -> (finalOtherSemester + averageSemester) / 2
|
||||
else -> (gradeSumOtherSemester + gradeSumSemester) / (gradeCountOtherSemester + gradeCountSemester)
|
||||
}
|
||||
|
||||
var gradeInt = floor(yearAverage.toDouble()).toInt()
|
||||
if (yearAverage % 1 >= 0.75)
|
||||
gradeInt++
|
||||
|
||||
b.yearAverageAfter.text = String.format(Locale.getDefault(), "%.02f", yearAverage)
|
||||
b.yearAverageAfter.background.colorFilter = PorterDuffColorFilter(Colors.gradeNameToColor(gradeInt.toString()), PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
|
||||
private fun refreshDataset() {
|
||||
gradeSumSemester = 0f
|
||||
gradeCountSemester = 0f
|
||||
averageSemester = 0f
|
||||
for (editorGrade in editorGrades) {
|
||||
var weight = editorGrade.weight
|
||||
if (app.appConfig.dontCountZeroToAverage && editorGrade.name == "0") {
|
||||
weight = 0f
|
||||
}
|
||||
val value = editorGrade.value * weight
|
||||
gradeSumSemester += value
|
||||
gradeCountSemester += weight
|
||||
}
|
||||
averageSemester = gradeSumSemester / gradeCountSemester
|
||||
refreshYearAverageAfter()
|
||||
b.averageAfter.text = String.format(Locale.getDefault(), "%.02f", averageSemester)
|
||||
var gradeInt = floor(averageSemester.toDouble()).toInt()
|
||||
if (averageSemester % 1 >= 0.75)
|
||||
gradeInt++
|
||||
b.averageAfter.background.colorFilter = PorterDuffColorFilter(Colors.gradeNameToColor(gradeInt.toString()), PorterDuff.Mode.MULTIPLY)
|
||||
b.listView.adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private fun refreshViews() {
|
||||
editorGrades.clear()
|
||||
|
||||
app.db.subjectDao().getById(App.profileId, subjectId).observe(this, Observer { subject ->
|
||||
if (subject == null || subject.id == -1L) {
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.error_occured)
|
||||
.content(R.string.error_no_subject_id)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive { _, _ -> activity.navigateUp() }
|
||||
.show()
|
||||
return@Observer
|
||||
}
|
||||
|
||||
gradeSumSemester = 0f
|
||||
gradeCountSemester = 0f
|
||||
averageSemester = 0f
|
||||
|
||||
app.db.gradeDao().getAllWhere(App.profileId, "subjectId = " + subject.id).observe(this, Observer { grades ->
|
||||
for (grade in grades) {
|
||||
if (grade.type == Grade.TYPE_NORMAL) {
|
||||
if (grade.weight < 0) {
|
||||
// do not show *normal* grades with negative weight - these are historical grades - Iuczniowie
|
||||
continue
|
||||
}
|
||||
var weight = grade.weight
|
||||
if (app.appConfig.dontCountZeroToAverage && grade.name == "0") {
|
||||
weight = 0f
|
||||
}
|
||||
val value = grade.value * weight
|
||||
if (grade.semester == semester) {
|
||||
gradeSumSemester += value
|
||||
gradeCountSemester += weight//(value > 0 ? weight : 0);
|
||||
editorGrades.add(EditorGrade(grade.id, grade.name, grade.value, grade.description + " - " + grade.category, grade.weight))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
averageSemester = gradeSumSemester / gradeCountSemester
|
||||
|
||||
if (averageMode == -1) {
|
||||
b.yearAverageContainer.visibility = View.GONE
|
||||
} else {
|
||||
b.yearAverageContainer.visibility = View.VISIBLE
|
||||
var gradeInt = floor(yearAverageBefore.toDouble()).toInt()
|
||||
if (yearAverageBefore % 1 >= 0.75)
|
||||
gradeInt++
|
||||
b.yearAverageBefore.text = String.format(Locale.getDefault(), "%.02f", yearAverageBefore)
|
||||
b.yearAverageBefore.background.colorFilter = PorterDuffColorFilter(Colors.gradeNameToColor(gradeInt.toString()), PorterDuff.Mode.MULTIPLY)
|
||||
|
||||
refreshYearAverageAfter()
|
||||
}
|
||||
|
||||
b.subjectName.text = subject.longName
|
||||
b.semesterName.text = getString(R.string.grades_semester_header_format, semester)
|
||||
var gradeInt = floor(averageSemester.toDouble()).toInt()
|
||||
if (averageSemester % 1 >= 0.75)
|
||||
gradeInt++
|
||||
b.averageBefore.text = String.format(Locale.getDefault(), "%.02f", averageSemester)
|
||||
b.averageBefore.background.colorFilter = PorterDuffColorFilter(Colors.gradeNameToColor(gradeInt.toString()), PorterDuff.Mode.MULTIPLY)
|
||||
b.averageAfter.text = String.format(Locale.getDefault(), "%.02f", averageSemester)
|
||||
b.averageAfter.background.colorFilter = PorterDuffColorFilter(Colors.gradeNameToColor(gradeInt.toString()), PorterDuff.Mode.MULTIPLY)
|
||||
b.listView.adapter!!.notifyDataSetChanged()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
data class EditorGrade(
|
||||
var id: Long,
|
||||
var name: String,
|
||||
var value: Float,
|
||||
var category: String,
|
||||
var weight: Float
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun modifyGradeChooser(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
|
||||
val popup = PopupMenu(v.context, v)
|
||||
popup.menu.add(0, 0, 0, R.string.grades_editor_change_grade)
|
||||
popup.menu.add(0, 1, 1, R.string.grades_editor_change_weight)
|
||||
|
||||
popup.setOnMenuItemClickListener { item ->
|
||||
if (item.itemId == 0) {
|
||||
modifyGradeName(v, editorGrade, callback)
|
||||
}
|
||||
if (item.itemId == 1) {
|
||||
modifyGradeWeight(v, editorGrade, callback)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
|
||||
fun addGradeHandler(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
|
||||
modifyGradeName(v, editorGrade) {
|
||||
modifyGradeWeight(v, editorGrade, callback)
|
||||
}
|
||||
}
|
||||
|
||||
fun modifyGradeName(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
|
||||
val popup = PopupMenu(v.context, v)
|
||||
popup.menu.add(0, 75, 0, "1-")
|
||||
popup.menu.add(0, 100, 1, "1")
|
||||
popup.menu.add(0, 150, 2, "1+")
|
||||
popup.menu.add(0, 175, 3, "2-")
|
||||
popup.menu.add(0, 200, 4, "2")
|
||||
popup.menu.add(0, 250, 5, "2+")
|
||||
popup.menu.add(0, 275, 6, "3-")
|
||||
popup.menu.add(0, 300, 7, "3")
|
||||
popup.menu.add(0, 350, 8, "3+")
|
||||
popup.menu.add(0, 375, 9, "4-")
|
||||
popup.menu.add(0, 400, 10, "4")
|
||||
popup.menu.add(0, 450, 11, "4+")
|
||||
popup.menu.add(0, 475, 12, "5-")
|
||||
popup.menu.add(0, 500, 13, "5")
|
||||
popup.menu.add(0, 550, 14, "5+")
|
||||
popup.menu.add(0, 575, 15, "6-")
|
||||
popup.menu.add(0, 600, 16, "6")
|
||||
popup.menu.add(0, 650, 17, "6+")
|
||||
popup.menu.add(0, 0, 18, "0")
|
||||
|
||||
popup.setOnMenuItemClickListener { item ->
|
||||
editorGrade.name = item.title.toString()
|
||||
editorGrade.value = item.itemId.toFloat() / 100
|
||||
callback()
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
|
||||
fun modifyGradeWeight(v: View, editorGrade: EditorGrade, callback: () -> Unit) {
|
||||
val popup = PopupMenu(v.context, v)
|
||||
for (i in 0..6) {
|
||||
popup.menu.add(0, i, i, v.context.getString(R.string.grades_editor_weight_format, DecimalFormat("#.##").format(i.toLong())))
|
||||
}
|
||||
popup.menu.add(1, 100, 100, v.context.getString(R.string.grades_editor_weight_other))
|
||||
|
||||
popup.setOnMenuItemClickListener { item ->
|
||||
if (item.itemId == 100) {
|
||||
MaterialDialog.Builder(v.context)
|
||||
.title(R.string.grades_editor_add_grade_title)
|
||||
.content(R.string.grades_editor_add_grade_weight)
|
||||
.inputType(InputType.TYPE_NUMBER_FLAG_SIGNED)
|
||||
.input(null, null) { _, input ->
|
||||
try {
|
||||
editorGrade.weight = input.toString().toFloat()
|
||||
callback()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.show()
|
||||
} else {
|
||||
editorGrade.weight = item.itemId.toFloat()
|
||||
callback()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
popup.show()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.home;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityCounterBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment.updateInterval;
|
||||
|
||||
public class CounterActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "CounterActivity";
|
||||
private App app;
|
||||
private ActivityCounterBinding b;
|
||||
|
||||
Timer timetableTimer;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
app = (App) getApplication();
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_counter, null, false);
|
||||
setContentView(b.getRoot());
|
||||
|
||||
timetableTimer = new Timer();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
private List<LessonFull> lessons = new ArrayList<>();
|
||||
|
||||
private void update() {
|
||||
// BELL SYNCING
|
||||
Time now = Time.getNow();
|
||||
Time syncedNow = now;
|
||||
//Time updateDiff = null;
|
||||
if (app.appConfig.bellSyncDiff != null) {
|
||||
if (app.appConfig.bellSyncMultiplier < 0) {
|
||||
// the bell is too fast, need to step further to go with it
|
||||
// add some time
|
||||
syncedNow = Time.sum(now, app.appConfig.bellSyncDiff);
|
||||
//Toast.makeText(c, "Bell sync diff is "+app.appConfig.bellSyncDiff.getStringHMS()+"\n\n Synced now is "+syncedNow.getStringHMS(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
if (app.appConfig.bellSyncMultiplier > 0) {
|
||||
// the bell is delayed, need to roll the "now" time back
|
||||
// subtract some time
|
||||
syncedNow = Time.diff(now, app.appConfig.bellSyncDiff);
|
||||
}
|
||||
}
|
||||
|
||||
assert counterTarget != null;
|
||||
if (lessons.size() == 0 || syncedNow.getValue() > counterTarget.getValue()) {
|
||||
findLessons(syncedNow);
|
||||
}
|
||||
else {
|
||||
scheduleUpdate(updateCounter(syncedNow));
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleUpdate(long newRefreshInterval) {
|
||||
try {
|
||||
timetableTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
runOnUiThread(() -> update());
|
||||
}
|
||||
}, newRefreshInterval);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void findLessons(Time syncedNow) {
|
||||
AsyncTask.execute(() -> {
|
||||
Date today = Date.getToday();
|
||||
lessons = app.db.lessonDao().getAllNearestNow(App.profileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today, syncedNow);
|
||||
|
||||
if (lessons != null && lessons.size() != 0) {
|
||||
Date displayingDate = lessons.get(0).lessonDate;
|
||||
if (displayingDate == null) {
|
||||
runOnUiThread(() -> scheduleUpdate(updateViews(null, syncedNow, 0, 0)));
|
||||
return;
|
||||
}
|
||||
int displayingWeekDay = displayingDate.getWeekDay();
|
||||
|
||||
Log.d(TAG, "Displaying date is "+displayingDate.getStringY_m_d()+", weekDay is "+displayingWeekDay);
|
||||
|
||||
int notPassedIndex = -1;
|
||||
int notPassedWeekDay = -1;
|
||||
//int firstIndex = -1;
|
||||
int lastIndex = -1;
|
||||
int index = 0;
|
||||
for (LessonFull lesson: lessons) {
|
||||
if (notPassedIndex == -1 && !lesson.lessonPassed) {
|
||||
if (lesson.lessonDate != null)
|
||||
displayingDate = lesson.lessonDate;
|
||||
displayingWeekDay = lesson.weekDay;
|
||||
notPassedIndex = index;
|
||||
notPassedWeekDay = lesson.weekDay;
|
||||
}
|
||||
if (lesson.weekDay == notPassedWeekDay) {
|
||||
/*if (firstIndex == -1)
|
||||
firstIndex = index;*/
|
||||
lastIndex = index;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// for safety
|
||||
/*if (firstIndex == -1)
|
||||
firstIndex++;*/
|
||||
if (notPassedIndex == -1)
|
||||
notPassedIndex++;
|
||||
if (lastIndex == -1)
|
||||
lastIndex++;
|
||||
|
||||
Log.d(TAG, "Not passed index is "+notPassedIndex);
|
||||
Log.d(TAG, "Last index is "+lastIndex);
|
||||
Log.d(TAG, "New Displaying date is "+displayingDate.getStringY_m_d()+", weekDay is "+displayingWeekDay);
|
||||
|
||||
Date finalDisplayingDate = displayingDate;
|
||||
int finalNotPassedIndex = notPassedIndex;
|
||||
int finalLastIndex = lastIndex;
|
||||
runOnUiThread(() -> scheduleUpdate(updateViews(finalDisplayingDate, syncedNow, finalNotPassedIndex, finalLastIndex)));
|
||||
}
|
||||
else {
|
||||
runOnUiThread(() -> scheduleUpdate(updateViews(null, syncedNow, 0, 0)));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private Time counterTarget = new Time(0, 0, 0);
|
||||
private static final short TIME_TILL = 0;
|
||||
private static final short TIME_LEFT = 1;
|
||||
private short counterType = TIME_LEFT;
|
||||
private long updateCounter(Time syncedNow) {
|
||||
Time diff = Time.diff(counterTarget, syncedNow);
|
||||
b.timeLeft.setText(counterType == TIME_TILL ? HomeFragment.timeTill(app, diff, app.appConfig.countInSeconds, "\n") : HomeFragment.timeLeft(app, diff, app.appConfig.countInSeconds, "\n"));
|
||||
return updateInterval(app, diff);
|
||||
}
|
||||
|
||||
private long updateViews(Date displayingDate, Time syncedNow, int notPassedIndex, int lastIndex) {
|
||||
long newRefreshInterval = 1000*5;
|
||||
|
||||
if (displayingDate == null) {
|
||||
return newRefreshInterval;
|
||||
}
|
||||
|
||||
int dayDiff = Date.diffDays(displayingDate, Date.getToday());
|
||||
if (displayingDate.getValue() != Date.getToday().getValue() && dayDiff == 0) {
|
||||
dayDiff++;
|
||||
}
|
||||
|
||||
LessonFull lessonFirst = lessons.get(dayDiff == 0 ? 0 : notPassedIndex);
|
||||
// should never be out of range
|
||||
LessonFull lessonLast = lessons.get(lastIndex);
|
||||
|
||||
boolean duringLessons = Time.inRange(lessonFirst.startTime, lessonLast.endTime, syncedNow) && dayDiff == 0;
|
||||
if (duringLessons) {
|
||||
LessonFull lessonCurrent = null;
|
||||
LessonFull lessonNext = null;
|
||||
|
||||
if (lessons.get(notPassedIndex).lessonCurrent) {
|
||||
lessonCurrent = lessons.get(notPassedIndex);
|
||||
if (lessons.size() > notPassedIndex+1 && lessons.get(notPassedIndex+1).weekDay == displayingDate.getWeekDay())
|
||||
lessonNext = lessons.get(notPassedIndex+1);
|
||||
}
|
||||
else {
|
||||
lessonNext = lessons.get(notPassedIndex);
|
||||
}
|
||||
|
||||
if (lessonCurrent != null) { // show time to the end of this lesson
|
||||
b.lessonName.setText(lessonCurrent.subjectLongName);
|
||||
|
||||
counterType = TIME_LEFT;
|
||||
counterTarget = lessonCurrent.endTime;
|
||||
newRefreshInterval = updateCounter(syncedNow);
|
||||
}
|
||||
else if (lessonNext != null) { // it's break time, show time to the start of next lesson
|
||||
b.lessonName.setText(R.string.lesson_break);
|
||||
|
||||
counterType = TIME_LEFT;
|
||||
counterTarget = lessonNext.startTime;
|
||||
newRefreshInterval = updateCounter(syncedNow);
|
||||
}
|
||||
else { // idk what it is now (during lessons, but not during lesson or a break)
|
||||
b.lessonName.setText(R.string.card_timetable_wtf);
|
||||
b.timeLeft.setText(R.string.card_timetable_wtf_report);
|
||||
newRefreshInterval = 1000*60*2;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (syncedNow.getValue() < lessonFirst.startTime.getValue()) {
|
||||
// before lessons
|
||||
b.lessonName.setText(R.string.lesson_break);
|
||||
|
||||
counterType = TIME_LEFT;
|
||||
counterTarget = lessonFirst.startTime;
|
||||
newRefreshInterval = updateCounter(syncedNow);
|
||||
}
|
||||
else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
return newRefreshInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
//Log.d(TAG, "OnDestroy");
|
||||
try {
|
||||
timetableTimer.cancel();
|
||||
timetableTimer.purge();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,568 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.home;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.PluralsRes;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardLuckyNumberBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardUpdateBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Subject;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.UPDATES_ON_PLAY_STORE;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_SEMESTER1_FINAL;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_SEMESTER1_PROPOSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_SEMESTER2_FINAL;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_SEMESTER2_PROPOSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_YEAR_FINAL;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_YEAR_PROPOSED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
private static final String TAG = "HomeFragment";
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentHomeBinding b = 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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_HOME, b.refreshLayout);
|
||||
});*/
|
||||
/*b.refreshLayout.setOnTouchListener((v, event) -> {
|
||||
d(TAG, "event "+event);
|
||||
event.setSource(0x10000000); // set a unique source
|
||||
activity.swipeRefreshLayout.onTouchEvent(event);
|
||||
return true;
|
||||
});*/
|
||||
/*b.refreshLayout.setOnDragListener((v, event) -> {
|
||||
activity.swipeRefreshLayout.onDragEvent(event);
|
||||
return true;
|
||||
});*/
|
||||
|
||||
b.composeButton.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE);
|
||||
b.composeButton.setOnClickListener((v -> {
|
||||
startActivity(new Intent(activity, MessagesComposeActivity.class));
|
||||
}));
|
||||
|
||||
//((TextView)v.findViewById(R.id.nextSync)).setText(getString(R.string.next_sync_format,Time.fromMillis(app.appJobs.syncJobTime).getStringHMS()));
|
||||
|
||||
|
||||
LayoutInflater layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
ViewGroup insertPoint = b.cardInsertPoint;
|
||||
assert layoutInflater != null;
|
||||
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && app.appConfig.mobidziennikOldMessages == -1) {
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title("Nowy moduł wiadomości")
|
||||
.content("Czy chcesz używać nowego modułu wiadomości?\n\nObejmuje lepsze powiadomienia, działa szybciej, pozwala na przeglądanie pobranych wiadomości bez internetu.\n\nNowy moduł (jeszcze) nie pozwala na wysyłanie wiadomości.")
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog, which) -> {
|
||||
if (app.appConfig.mobidziennikOldMessages != 0) {
|
||||
// need to change old to new
|
||||
app.appConfig.mobidziennikOldMessages = 0;
|
||||
app.saveConfig("mobidziennikOldMessages");
|
||||
MainActivity.Companion.setUseOldMessages(false);
|
||||
activity.loadProfile(App.profileId);
|
||||
}
|
||||
}))
|
||||
.onNegative(((dialog, which) -> {
|
||||
if (app.appConfig.mobidziennikOldMessages != 1) {
|
||||
// need to change from ?? to old
|
||||
app.appConfig.mobidziennikOldMessages = 1;
|
||||
app.saveConfig("mobidziennikOldMessages");
|
||||
MainActivity.Companion.setUseOldMessages(true);
|
||||
activity.loadProfile(App.profileId);
|
||||
}
|
||||
}))
|
||||
.show();
|
||||
}
|
||||
|
||||
b.mobidziennikMessagesSwitch.setVisibility(app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK ? View.VISIBLE : View.GONE);
|
||||
b.mobidziennikMessagesSwitch.setOnClickListener((v -> {
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title("Nowy moduł wiadomości")
|
||||
.content("Czy chcesz używać nowego modułu wiadomości?\n\nObejmuje lepsze powiadomienia, działa szybciej, pozwala na przeglądanie pobranych wiadomości bez internetu.\n\nNowy moduł (jeszcze) nie pozwala na wysyłanie wiadomości.")
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog, which) -> {
|
||||
if (app.appConfig.mobidziennikOldMessages != 0) {
|
||||
// need to change old to new
|
||||
app.appConfig.mobidziennikOldMessages = 0;
|
||||
app.saveConfig("mobidziennikOldMessages");
|
||||
MainActivity.Companion.setUseOldMessages(false);
|
||||
activity.loadProfile(App.profileId);
|
||||
}
|
||||
}))
|
||||
.onNegative(((dialog, which) -> {
|
||||
if (app.appConfig.mobidziennikOldMessages != 1) {
|
||||
// need to change from ?? to old
|
||||
app.appConfig.mobidziennikOldMessages = 1;
|
||||
app.saveConfig("mobidziennikOldMessages");
|
||||
MainActivity.Companion.setUseOldMessages(true);
|
||||
activity.loadProfile(App.profileId);
|
||||
}
|
||||
}))
|
||||
.show();
|
||||
}));
|
||||
|
||||
/*if (!app.profile.loggedIn) {
|
||||
View cardLoginRoot = layoutInflater.inflate(R.layout.card_login, null);
|
||||
|
||||
CardView cardLogin = cardLoginRoot.findViewById(R.id.cardLogin);
|
||||
cardLogin.setVisibility(app.profile.loggedIn ? View.GONE : View.VISIBLE);
|
||||
Button cardLoginButton = cardLoginRoot.findViewById(R.id.cardLoginButton);
|
||||
buttonAddDrawable(c, cardLoginButton, CommunityMaterial.Icon.cmd_arrow_right);
|
||||
cardLoginButton.setOnClickListener((v1 -> {
|
||||
new Handler().postDelayed(() -> {
|
||||
a.runOnUiThread(() -> {
|
||||
Intent i = new Intent("android.intent.action.MAIN")
|
||||
.putExtra(MainActivity.ACTION_CHANGE_CURRENT_VIEW, "yes, sure")
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_SETTINGS)
|
||||
.putExtra("settingsPage", SettingsFragment.PAGE_REGISTER);
|
||||
app.getContext().sendBroadcast(i);
|
||||
});
|
||||
}, 100);
|
||||
}));
|
||||
|
||||
insertPoint.addView(cardLoginRoot, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
if (app.appConfig.updateVersion != null && !app.appConfig.updateVersion.equals("")) {
|
||||
if (app.appConfig.updateVersion.equals(BuildConfig.VERSION_NAME)) {
|
||||
app.appConfig.updateVersion = "";
|
||||
app.saveConfig("updateVersion");
|
||||
}
|
||||
else {
|
||||
CardUpdateBinding b;
|
||||
b = DataBindingUtil.inflate(layoutInflater, R.layout.card_update, insertPoint, false);
|
||||
insertPoint.addView(b.getRoot());
|
||||
|
||||
b.cardUpdateText.setText(getString(R.string.card_update_text_format, BuildConfig.VERSION_NAME, app.appConfig.updateVersion));
|
||||
buttonAddDrawable(activity, b.cardUpdateButton, CommunityMaterial.Icon.cmd_arrow_right);
|
||||
b.cardUpdateButton.setOnClickListener((v1 -> {
|
||||
if (UPDATES_ON_PLAY_STORE) {
|
||||
Utils.openGooglePlay(activity, "pl.szczodrzynski.edziennik");
|
||||
}
|
||||
else {
|
||||
BootReceiver.update_url = app.appConfig.updateUrl;
|
||||
BootReceiver.update_filename = app.appConfig.updateFilename;
|
||||
BootReceiver.update_download_id = BootReceiver.downloadFile(app);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (app.profile.getLuckyNumberEnabled()
|
||||
&& app.profile.getLuckyNumber() != -1
|
||||
&& app.profile.getLuckyNumberDate() != null && app.profile.getLuckyNumberDate().getValue() == Date.getToday().getValue()) {
|
||||
CardLuckyNumberBinding b;
|
||||
b = DataBindingUtil.inflate(layoutInflater, R.layout.card_lucky_number, insertPoint, false);
|
||||
insertPoint.addView(b.getRoot());
|
||||
|
||||
b.cardLuckyNumberTitle.setText(getString(R.string.card_lucky_number_title_format, app.profile.getLuckyNumber()));
|
||||
if (app.profile.getStudentNumber() == -1) {
|
||||
b.cardLuckyNumberText.setText(R.string.card_lucky_number_not_set);
|
||||
}
|
||||
else {
|
||||
b.cardLuckyNumberText.setText(getString(R.string.card_lucky_number_text_format, app.profile.getStudentNumber()));
|
||||
}
|
||||
|
||||
b.cardLuckyNumber.setOnClickListener(v1 -> setNumberDialog());
|
||||
}
|
||||
|
||||
timetableCard = new HomeTimetableCard(app, activity, this, layoutInflater, insertPoint);
|
||||
timetableCard.run();
|
||||
|
||||
configCardGrades(activity, layoutInflater, activity, insertPoint);
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_set_student_number)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_counter)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
setNumberDialog();
|
||||
}),
|
||||
new BottomSheetSeparatorItem(true)
|
||||
);
|
||||
activity.gainAttention();
|
||||
}
|
||||
|
||||
public void setNumberDialog() {
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.card_lucky_number_set_title)
|
||||
.content(R.string.card_lucky_number_set_text)
|
||||
.inputType(InputType.TYPE_CLASS_NUMBER)
|
||||
.input(null, app.profile.getStudentNumber() == -1 ? "" : Utils.intToStr(app.profile.getStudentNumber()), (dialog, input) -> {
|
||||
try {
|
||||
app.profile.setStudentNumber(Utils.strToInt(input.toString()));
|
||||
AsyncTask.execute(() -> app.profileSaveAsync());
|
||||
activity.reloadTarget();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Toast.makeText(activity, R.string.incorrect_format, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
public static String plural(Context c, @PluralsRes int resId, int value) {
|
||||
return c.getResources().getQuantityString(resId, value, value);
|
||||
}
|
||||
|
||||
public static long updateInterval(App app, Time diff) {
|
||||
//Log.d(TAG, "Millis is "+System.currentTimeMillis() % 1000+", update in "+(1000-(System.currentTimeMillis() % 1000)));
|
||||
if (app.appConfig.countInSeconds) {
|
||||
return 1000-(System.currentTimeMillis() % 1000);
|
||||
}
|
||||
if (diff.minute > 5) {
|
||||
//Log.d(TAG, "60 secs");
|
||||
return 60000-(System.currentTimeMillis() % 60000);
|
||||
}
|
||||
else if (diff.minute >= 1) {
|
||||
//Log.d(TAG, "3 secs");
|
||||
return 3000-(System.currentTimeMillis() % 3000);
|
||||
}
|
||||
else if (diff.second >= 40) {
|
||||
//Log.d(TAG, "2 secs");
|
||||
return 2000-(System.currentTimeMillis() % 2000);
|
||||
}
|
||||
else {
|
||||
Log.d(TAG, "1 sec");
|
||||
return 1000-(System.currentTimeMillis() % 1000);
|
||||
}
|
||||
}
|
||||
|
||||
public static String timeTill(Context c, Time t1, Time t2) {
|
||||
return timeTill(c, Time.diff(t1, t2));
|
||||
}
|
||||
public static String timeTill(Context c, Time diff) {
|
||||
return timeTill(c, diff, false);
|
||||
}
|
||||
public static String timeTill(Context c, Time diff, boolean countInSeconds) {
|
||||
return timeTill(c, diff, countInSeconds, " ");
|
||||
}
|
||||
public static String timeTill(Context c, Time diff, boolean countInSeconds, String textDelimiter) {
|
||||
if (countInSeconds) {
|
||||
int seconds = diff.second + diff.minute * 60 + diff.hour * 3600;
|
||||
return plural(c, R.plurals.time_till_text, seconds)+textDelimiter+plural(c, R.plurals.time_till_seconds, seconds);
|
||||
}
|
||||
if (diff.hour < 1 && diff.minute < 1) {
|
||||
return plural(c, R.plurals.time_till_text, diff.second)+textDelimiter+plural(c, R.plurals.time_till_seconds, diff.second);
|
||||
}
|
||||
else if (diff.hour < 1 && diff.minute < 5) {
|
||||
return plural(c, R.plurals.time_till_text, diff.minute)+textDelimiter+plural(c, R.plurals.time_till_minutes, diff.minute)+" "+plural(c, R.plurals.time_till_seconds, diff.second);
|
||||
}
|
||||
else if (diff.hour < 1) {
|
||||
return plural(c, R.plurals.time_till_text, diff.minute)+textDelimiter+plural(c, R.plurals.time_till_minutes, diff.minute);
|
||||
}
|
||||
else { // diff.hour > 1
|
||||
return plural(c, R.plurals.time_till_text, diff.hour)+textDelimiter+plural(c, R.plurals.time_till_hours, diff.hour)+" "+plural(c, R.plurals.time_till_minutes, diff.minute);
|
||||
}
|
||||
}
|
||||
|
||||
public static String timeLeft(Context c, Time diff) {
|
||||
return timeLeft(c, diff, false);
|
||||
}
|
||||
public static String timeLeft(Context c, Time diff, boolean countInSeconds) {
|
||||
return timeLeft(c, diff, countInSeconds, " ");
|
||||
}
|
||||
public static String timeLeft(Context c, Time diff, boolean countInSeconds, String textDelimiter) {
|
||||
if (countInSeconds) {
|
||||
int seconds = diff.second + diff.minute * 60 + diff.hour * 3600;
|
||||
return plural(c, R.plurals.time_left_text, seconds)+textDelimiter+plural(c, R.plurals.time_left_seconds, seconds);
|
||||
}
|
||||
if (diff.hour < 1 && diff.minute < 1) {
|
||||
return plural(c, R.plurals.time_left_text, diff.second)+textDelimiter+plural(c, R.plurals.time_left_seconds, diff.second);
|
||||
}
|
||||
else if (diff.hour < 1 && diff.minute < 5) {
|
||||
return plural(c, R.plurals.time_left_text, diff.minute)+textDelimiter+plural(c, R.plurals.time_left_minutes, diff.minute)+" "+plural(c, R.plurals.time_left_seconds, diff.second);
|
||||
}
|
||||
else if (diff.hour < 1) {
|
||||
return plural(c, R.plurals.time_left_text, diff.minute)+textDelimiter+plural(c, R.plurals.time_left_minutes, diff.minute);
|
||||
}
|
||||
else { // diff.hour > 1
|
||||
return plural(c, R.plurals.time_left_text, diff.hour)+textDelimiter+plural(c, R.plurals.time_left_hours, diff.hour)+" "+plural(c, R.plurals.time_left_minutes, diff.minute);
|
||||
}
|
||||
}
|
||||
|
||||
public static void buttonAddDrawable(Context c, Button button, CommunityMaterial.Icon icon)
|
||||
{
|
||||
button.setCompoundDrawables(null, null, new IconicsDrawable(c)
|
||||
.icon(icon)
|
||||
.color(IconicsColor.colorInt(Utils.getAttr(c, android.R.attr.textColorPrimary)))
|
||||
.size(IconicsSize.dp(16)), null);
|
||||
}
|
||||
public static Date findDateWithLessons(int profileId, List<LessonFull> lessons) {
|
||||
return findDateWithLessons(profileId, lessons, 0);
|
||||
}
|
||||
public static Date findDateWithLessons(int profileId, List<LessonFull> lessons, int nextDayHourThreshold) {
|
||||
return findDateWithLessons(profileId, lessons, Time.getNow(), nextDayHourThreshold);
|
||||
}
|
||||
public static Date findDateWithLessons(int profileId, List<LessonFull> lessons, Time now) {
|
||||
return findDateWithLessons(profileId, lessons, now, 0);
|
||||
}
|
||||
public static Date findDateWithLessons(int profileId, @NonNull List<LessonFull> lessons, Time now, int nextDayHourThreshold) {
|
||||
now = now.clone().stepForward(-nextDayHourThreshold, 0, 0);
|
||||
Date displayingDate = Date.getToday();
|
||||
int displayingWeekDay = displayingDate.getWeekDay();
|
||||
//boolean foundSomething = false;
|
||||
//int weekDayNum = displayingDate.getWeekDay();//Week.getTodayWeekDay();
|
||||
//int checkedDays = 0;
|
||||
|
||||
for (LessonFull lesson: lessons) {
|
||||
if (lesson.profileId != profileId)
|
||||
continue;
|
||||
if (lesson.weekDay == displayingWeekDay
|
||||
&& now.getValue() <= lesson.endTime.getValue()) {
|
||||
return lesson.lessonDate;
|
||||
}
|
||||
if (lesson.weekDay != displayingWeekDay) {
|
||||
return lesson.lessonDate;
|
||||
}
|
||||
}
|
||||
return displayingDate;
|
||||
|
||||
/*while (!foundSomething && checkedDays < 14)
|
||||
{
|
||||
weekDay = profile.timetable.weekdays[displayingDate.getWeekDay()];
|
||||
if (weekDay.lessons.size() == 0) // this day has no lessons
|
||||
{
|
||||
displayingDate.stepForward(0, 0, 1);
|
||||
checkedDays++;
|
||||
continue;
|
||||
}
|
||||
if (displayingDate.getWeekDay() == Week.getTodayWeekDay() // today
|
||||
&& now.getValue() > weekDay.lessons.get(weekDay.lessons.size() - 1).endTime.getValue()) // this day has lessons, but last lesson is over already
|
||||
{
|
||||
displayingDate.stepForward(0, 0, 1);
|
||||
checkedDays++;
|
||||
continue;
|
||||
}
|
||||
// this day has lessons, and we are during the lessons
|
||||
foundSomething = true;
|
||||
}
|
||||
return displayingDate;*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void updateCardGrades(Context c, Activity a, View root, int maxWidthPx) {
|
||||
if (a == null || !isAdded())
|
||||
return;
|
||||
TextView cardGradesNoData = root.findViewById(R.id.cardGradesNoData);
|
||||
|
||||
app.db.gradeDao().getAllWhere(App.profileId, "gradeSemester = "+ app.profile.getCurrentSemester() +" AND addedDate > "+(System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000)).observe(this, grades -> {
|
||||
List<ItemGradesSubjectModel> subjectList = new ArrayList<>();
|
||||
|
||||
// now we have all grades from the newest to the oldest
|
||||
for (GradeFull grade: grades) {
|
||||
ItemGradesSubjectModel model = ItemGradesSubjectModel.searchModelBySubjectId(subjectList, grade.subjectId);
|
||||
if (model == null) {
|
||||
subjectList.add(new ItemGradesSubjectModel(app.profile, new Subject(App.profileId, grade.subjectId, grade.subjectLongName, grade.subjectShortName), new ArrayList<>(), new ArrayList<>()));
|
||||
model = ItemGradesSubjectModel.searchModelBySubjectId(subjectList, grade.subjectId);
|
||||
}
|
||||
if (model != null) { // should always be not null
|
||||
model.grades1.add(grade);
|
||||
}
|
||||
}
|
||||
|
||||
float scale = c.getResources().getDisplayMetrics().density;
|
||||
int _5dp = (int) (5 * scale + 0.5f);
|
||||
int _8dp = (int) (8 * scale + 0.5f);
|
||||
|
||||
LinearLayout cardGradesList = root.findViewById(R.id.cardGradesList);
|
||||
cardGradesList.removeAllViews();
|
||||
|
||||
LinearLayout.LayoutParams textLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
textLayoutParams.setMargins(0, 0, _5dp, 0);
|
||||
|
||||
LinearLayout.LayoutParams linearLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
linearLayoutParams.setMargins(_8dp, 0, _8dp, _5dp);
|
||||
|
||||
//Log.d(TAG, "maxWidthPx "+maxWidthPx);
|
||||
|
||||
int count = 0;
|
||||
|
||||
if (subjectList.size() > 0) {
|
||||
for (ItemGradesSubjectModel subjectModel : subjectList) {
|
||||
if (count++ >= 8) {
|
||||
//continue;
|
||||
}
|
||||
LinearLayout gradeItem = new LinearLayout(cardGradesList.getContext());
|
||||
gradeItem.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
int totalWidthPx = 0;//subjectName.getMeasuredWidth() + _5dp;
|
||||
|
||||
|
||||
boolean ellipsized = false;
|
||||
|
||||
for (GradeFull grade : subjectModel.grades1) {
|
||||
if (ellipsized)
|
||||
continue;
|
||||
int gradeColor;
|
||||
if (app.profile.getGradeColorMode() == Profile.COLOR_MODE_DEFAULT) {
|
||||
gradeColor = grade.color;
|
||||
}
|
||||
else {
|
||||
gradeColor = Colors.gradeToColor(grade);
|
||||
}
|
||||
|
||||
TextView gradeName = new TextView(gradeItem.getContext());
|
||||
gradeName.setText(grade.name);
|
||||
if (grade.type == TYPE_SEMESTER1_PROPOSED
|
||||
|| grade.type == TYPE_SEMESTER2_PROPOSED) {
|
||||
gradeName.setText(getString(R.string.grade_semester_proposed_format, grade.name));
|
||||
}
|
||||
else if (grade.type == TYPE_SEMESTER1_FINAL
|
||||
|| grade.type == TYPE_SEMESTER2_FINAL) {
|
||||
gradeName.setText(getString(R.string.grade_semester_final_format, grade.name));
|
||||
}
|
||||
else if (grade.type == TYPE_YEAR_PROPOSED) {
|
||||
gradeName.setText(getString(R.string.grade_year_proposed_format, grade.name));
|
||||
}
|
||||
else if (grade.type == TYPE_YEAR_FINAL) {
|
||||
gradeName.setText(getString(R.string.grade_year_final_format, grade.name));
|
||||
}
|
||||
gradeName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.25 ? 0xff000000 : 0xffffffff);
|
||||
gradeName.setTypeface(null, Typeface.BOLD);
|
||||
gradeName.setBackgroundResource(R.drawable.bg_rounded_4dp);
|
||||
gradeName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY));
|
||||
gradeName.setPadding(_5dp, 0, _5dp, 0);
|
||||
|
||||
gradeName.measure(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
totalWidthPx += gradeName.getMeasuredWidth() + _5dp;
|
||||
//Log.d(TAG, "totalWidthPx "+totalWidthPx);
|
||||
if (totalWidthPx >= (float)maxWidthPx / 1.5f) {
|
||||
ellipsized = true;
|
||||
TextView ellipsisText = new TextView(gradeItem.getContext());
|
||||
ellipsisText.setText(R.string.ellipsis);
|
||||
ellipsisText.setTextAppearance(gradeItem.getContext(), R.style.NavView_TextView);
|
||||
ellipsisText.setTypeface(null, Typeface.BOLD);
|
||||
ellipsisText.setPadding(0, 0, 0, 0);
|
||||
gradeItem.addView(ellipsisText, textLayoutParams);
|
||||
}
|
||||
else {
|
||||
gradeItem.addView(gradeName, textLayoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
TextView subjectName = new TextView(gradeItem.getContext());
|
||||
Subject subject = subjectModel.subject;
|
||||
subjectName.setText(" z "+(subject != null ? subject.longName : ""));
|
||||
subjectName.setEllipsize(TextUtils.TruncateAt.END);
|
||||
subjectName.setSingleLine();
|
||||
subjectName.measure(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
//Log.d(TAG, "subjectName.width "+totalWidthPx);
|
||||
//subjectName.setMaxWidth(maxWidthPx - totalWidthPx);
|
||||
|
||||
gradeItem.addView(subjectName, textLayoutParams);
|
||||
|
||||
cardGradesList.addView(gradeItem, linearLayoutParams);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cardGradesNoData.setVisibility(View.VISIBLE);
|
||||
cardGradesList.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
Button cardGradesButton = root.findViewById(R.id.cardGradesButton);
|
||||
buttonAddDrawable(c, cardGradesButton, CommunityMaterial.Icon.cmd_arrow_right);
|
||||
cardGradesButton.setOnClickListener((v1 -> new Handler().postDelayed(() -> a.runOnUiThread(() -> {
|
||||
activity.loadTarget(MainActivity.DRAWER_ITEM_GRADES, null);
|
||||
}), 100)));
|
||||
|
||||
//new Handler().postDelayed(() -> a.runOnUiThread(() -> updateCardGrades(c, a, root)), newRefreshInterval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (timetableCard != null)
|
||||
timetableCard.destroy();
|
||||
}
|
||||
|
||||
private void configCardGrades(Context c, LayoutInflater layoutInflater, Activity a, ViewGroup insertPoint) {
|
||||
View root = layoutInflater.inflate(R.layout.card_grades, null);
|
||||
DisplayMetrics displayMetrics = c.getResources().getDisplayMetrics();
|
||||
updateCardGrades(c, a, root, displayMetrics.widthPixels - Utils.dpToPx((app.appConfig.miniDrawerVisible ? 72 : 0)/*miniDrawer size*/ + 24 + 24/*left and right offsets*/ + 16/*ellipsize width*/));
|
||||
insertPoint.addView(root, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
|
||||
private HomeTimetableCard timetableCard;
|
||||
}
|
@ -0,0 +1,473 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.home;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardTimetableBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LessonChange.TYPE_CANCELLED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LessonChange.TYPE_CHANGE;
|
||||
import static pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment.updateInterval;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
|
||||
public class HomeTimetableCard {
|
||||
private static final String TAG = "HomeTimetableCard";
|
||||
private App app;
|
||||
private MainActivity a;
|
||||
private HomeFragment f;
|
||||
private LayoutInflater layoutInflater;
|
||||
private ViewGroup insertPoint;
|
||||
private CardTimetableBinding b;
|
||||
private Timer timetableTimer;
|
||||
private Time bellSyncTime = null;
|
||||
|
||||
public HomeTimetableCard(App app, MainActivity a, HomeFragment f, LayoutInflater layoutInflater, ViewGroup insertPoint) {
|
||||
this.app = app;
|
||||
this.a = a;
|
||||
this.f = f;
|
||||
this.layoutInflater = layoutInflater;
|
||||
this.insertPoint = insertPoint;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
timetableTimer = new Timer();
|
||||
b = DataBindingUtil.inflate(layoutInflater, R.layout.card_timetable, null, false);
|
||||
update();
|
||||
insertPoint.addView(b.getRoot(), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
b.cardTimetableFullscreenCounter.setOnClickListener((v -> {
|
||||
Intent intent = new Intent(a, CounterActivity.class);
|
||||
a.startActivity(intent);
|
||||
}));
|
||||
|
||||
b.cardTimetableBellSync.setOnClickListener(v -> {
|
||||
if (bellSyncTime == null) {
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(R.string.bell_sync_cannot_now)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
}
|
||||
else {
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(app.getString(R.string.bell_sync_howto, bellSyncTime.getStringHM())+
|
||||
(app.appConfig.bellSyncDiff != null ?
|
||||
""+app.getString(R.string.bell_sync_current_dialog, (app.appConfig.bellSyncMultiplier == -1 ? "-" : "+")+app.appConfig.bellSyncDiff.getStringHMS())
|
||||
: ""))
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.neutralText(R.string.reset)
|
||||
.onPositive((dialog, which) -> {
|
||||
Time bellDiff = Time.diff(Time.getNow(), bellSyncTime);
|
||||
app.appConfig.bellSyncDiff = bellDiff;
|
||||
app.appConfig.bellSyncMultiplier = (bellSyncTime.getValue() > Time.getNow().getValue() ? -1 : 1);
|
||||
app.saveConfig("bellSyncDiff", "bellSyncMultiplier");
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(app.getString(R.string.bell_sync_results, (bellSyncTime.getValue() > Time.getNow().getValue() ? "-" : "+"), bellDiff.getStringHMS()))
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
})
|
||||
.onNeutral((dialog, which) -> {
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(R.string.bell_sync_reset_confirm)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog1, which1) -> {
|
||||
app.appConfig.bellSyncDiff = null;
|
||||
app.appConfig.bellSyncMultiplier = 0;
|
||||
app.saveConfig("bellSyncDiff", "bellSyncMultiplier");
|
||||
}))
|
||||
.show();
|
||||
})
|
||||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
HomeFragment.buttonAddDrawable(a, b.cardTimetableButton, CommunityMaterial.Icon.cmd_arrow_right);
|
||||
}
|
||||
|
||||
private List<LessonFull> lessons = new ArrayList<>();
|
||||
private List<EventFull> events = new ArrayList<>();
|
||||
|
||||
private void update() {
|
||||
//Log.d(TAG, "Now "+System.currentTimeMillis());
|
||||
if (a == null || !f.isAdded())
|
||||
return;
|
||||
// BELL SYNCING
|
||||
Time now = Time.getNow();
|
||||
Time syncedNow = now;
|
||||
//Time updateDiff = null;
|
||||
if (app.appConfig.bellSyncDiff != null) {
|
||||
if (app.appConfig.bellSyncMultiplier < 0) {
|
||||
// the bell is too fast, need to step further to go with it
|
||||
// add some time
|
||||
syncedNow = Time.sum(now, app.appConfig.bellSyncDiff);
|
||||
//Toast.makeText(c, "Bell sync diff is "+app.appConfig.bellSyncDiff.getStringHMS()+"\n\n Synced now is "+syncedNow.getStringHMS(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
if (app.appConfig.bellSyncMultiplier > 0) {
|
||||
// the bell is delayed, need to roll the "now" time back
|
||||
// subtract some time
|
||||
syncedNow = Time.diff(now, app.appConfig.bellSyncDiff);
|
||||
}
|
||||
}
|
||||
|
||||
assert counterTarget != null;
|
||||
if (lessons.size() == 0 || syncedNow.getValue() > counterTarget.getValue()) {
|
||||
findLessons(syncedNow);
|
||||
}
|
||||
else {
|
||||
scheduleUpdate(updateCounter(syncedNow));
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleUpdate(long newRefreshInterval) {
|
||||
try {
|
||||
timetableTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
a.runOnUiThread(() -> update());
|
||||
}
|
||||
}, newRefreshInterval);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void findLessons(Time syncedNow) {
|
||||
AsyncTask.execute(() -> {
|
||||
Date today = Date.getToday();
|
||||
lessons = app.db.lessonDao().getAllNearestNow(App.profileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today, syncedNow);
|
||||
|
||||
if (lessons != null && lessons.size() != 0) {
|
||||
Date displayingDate = lessons.get(0).lessonDate;
|
||||
if (displayingDate == null) {
|
||||
a.runOnUiThread(() -> scheduleUpdate(updateViews(null, syncedNow, 0, 0)));
|
||||
return;
|
||||
}
|
||||
int displayingWeekDay = displayingDate.getWeekDay();
|
||||
|
||||
Log.d(TAG, "Displaying date is "+displayingDate.getStringY_m_d()+", weekDay is "+displayingWeekDay);
|
||||
|
||||
int notPassedIndex = -1;
|
||||
int notPassedWeekDay = -1;
|
||||
//int firstIndex = -1;
|
||||
int lastIndex = -1;
|
||||
int index = 0;
|
||||
for (LessonFull lesson: lessons) {
|
||||
if (notPassedIndex == -1 && !lesson.lessonPassed) {
|
||||
if (lesson.lessonDate != null)
|
||||
displayingDate = lesson.lessonDate;
|
||||
displayingWeekDay = lesson.weekDay;
|
||||
notPassedIndex = index;
|
||||
notPassedWeekDay = lesson.weekDay;
|
||||
}
|
||||
if (lesson.weekDay == notPassedWeekDay) {
|
||||
/*if (firstIndex == -1)
|
||||
firstIndex = index;*/
|
||||
lastIndex = index;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// for safety
|
||||
/*if (firstIndex == -1)
|
||||
firstIndex++;*/
|
||||
if (notPassedIndex == -1)
|
||||
notPassedIndex++;
|
||||
if (lastIndex == -1)
|
||||
lastIndex++;
|
||||
|
||||
Log.d(TAG, "Not passed index is "+notPassedIndex);
|
||||
Log.d(TAG, "Last index is "+lastIndex);
|
||||
Log.d(TAG, "New Displaying date is "+displayingDate.getStringY_m_d()+", weekDay is "+displayingWeekDay);
|
||||
events = app.db.eventDao().getAllByDateNow(App.profileId, displayingDate);
|
||||
|
||||
Date finalDisplayingDate = displayingDate;
|
||||
int finalNotPassedIndex = notPassedIndex;
|
||||
int finalLastIndex = lastIndex;
|
||||
a.runOnUiThread(() -> scheduleUpdate(updateViews(finalDisplayingDate, syncedNow, finalNotPassedIndex, finalLastIndex)));
|
||||
}
|
||||
else {
|
||||
a.runOnUiThread(() -> scheduleUpdate(updateViews(null, syncedNow, 0, 0)));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private Time counterTarget = new Time(0, 0, 0);
|
||||
private static final short TIME_TILL = 0;
|
||||
private static final short TIME_LEFT = 1;
|
||||
private short counterType = TIME_TILL;
|
||||
private long updateCounter(Time syncedNow) {
|
||||
Time diff = Time.diff(counterTarget, syncedNow);
|
||||
b.cardTimetableTimeLeft.setText(counterType == TIME_TILL ? HomeFragment.timeTill(app, diff, app.appConfig.countInSeconds) : HomeFragment.timeLeft(app, diff, app.appConfig.countInSeconds));
|
||||
bellSyncTime = counterTarget;
|
||||
b.cardTimetableFullscreenCounter.setVisibility(View.VISIBLE);
|
||||
return updateInterval(app, diff);
|
||||
}
|
||||
|
||||
private long updateViews(Date displayingDate, Time syncedNow, int notPassedIndex, int lastIndex) {
|
||||
//Date weekEnd = Date.getToday().stepForward(0, 0, 6 - Week.getTodayWeekDay()); // Sunday of the current week
|
||||
|
||||
if (displayingDate == null) {
|
||||
b.cardTimetableTitle.setText(R.string.card_timetable_no_timetable);
|
||||
b.cardTimetableNoData.setVisibility(View.VISIBLE);
|
||||
b.cardTimetableContent.setVisibility(View.GONE);
|
||||
return 1000*60*30;
|
||||
}
|
||||
|
||||
// at this point lessons.size() must be greater than 0
|
||||
|
||||
int displayingWeekDay = displayingDate.getWeekDay();
|
||||
|
||||
|
||||
|
||||
String weekDayStr = Week.getFullDayName(displayingWeekDay);
|
||||
int dayDiff = Date.diffDays(displayingDate, Date.getToday());
|
||||
if (displayingDate.getValue() != Date.getToday().getValue() && dayDiff == 0) {
|
||||
dayDiff++;
|
||||
}
|
||||
String dayDiffStr = (dayDiff == 0 ? app.getString(R.string.day_today_format, weekDayStr) : (dayDiff == 1 ? app.getString(R.string.day_tomorrow_format,weekDayStr) : app.getString(R.string.day_other_format, weekDayStr, displayingDate.getStringDm())));
|
||||
|
||||
b.cardTimetableTitle.setText(app.getString(R.string.card_timetable_title, dayDiffStr));
|
||||
|
||||
long newRefreshInterval = 1000*5; // 5 seconds
|
||||
|
||||
b.cardTimetableNoData.setVisibility(View.GONE);
|
||||
b.cardTimetableContent.setVisibility(View.VISIBLE);
|
||||
|
||||
LessonFull lessonFirst = lessons.get(dayDiff == 0 ? 0 : notPassedIndex);
|
||||
// should never be out of range
|
||||
LessonFull lessonLast = lessons.get(lastIndex);
|
||||
|
||||
boolean duringLessons = Time.inRange(lessonFirst.startTime, lessonLast.endTime, syncedNow) && dayDiff == 0;
|
||||
if (!duringLessons) {
|
||||
|
||||
LessonFull lessonSecond = null;
|
||||
if (lessons.size() > notPassedIndex+1 && lessons.get(notPassedIndex+1).weekDay == displayingDate.getWeekDay())
|
||||
lessonSecond = lessons.get(notPassedIndex+1);
|
||||
|
||||
b.cardTimetableType.setText(R.string.card_timetable_lesson_duration);
|
||||
b.cardTimetableSummary.setText(app.getString(R.string.card_timetable_lesson_duration_format, lessonFirst.startTime.getStringHM(), lessonLast.endTime.getStringHM()));
|
||||
if (dayDiff == 0) {
|
||||
counterTarget = lessonFirst.startTime;
|
||||
counterType = TIME_TILL;
|
||||
newRefreshInterval = updateCounter(syncedNow);
|
||||
}
|
||||
else {
|
||||
b.cardTimetableTimeLeft.setText("");
|
||||
newRefreshInterval = 1000*60*30;
|
||||
b.cardTimetableFullscreenCounter.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
String lessonFirstStr = null;
|
||||
if (lessonFirst.changeId != 0) {
|
||||
if (lessonFirst.changeType == TYPE_CANCELLED) {
|
||||
lessonFirstStr = "<del>" + bs(lessonFirst.getSubjectLongName()) + "</del>";
|
||||
} else if (lessonFirst.changeType == TYPE_CHANGE) {
|
||||
lessonFirstStr = "<i>" + bs(lessonFirst.getSubjectLongName()) + "</i>";
|
||||
}
|
||||
} else {
|
||||
lessonFirstStr = bs(lessonFirst.subjectLongName);
|
||||
}
|
||||
String lessonSecondStr = null;
|
||||
if (lessonSecond != null) {
|
||||
if (lessonSecond.changeId != 0) {
|
||||
if (lessonSecond.changeType == TYPE_CANCELLED) {
|
||||
lessonSecondStr = "<del>" + bs(lessonSecond.getSubjectLongName()) + "</del>";
|
||||
} else if (lessonSecond.changeType == TYPE_CHANGE) {
|
||||
lessonSecondStr = "<i>" + bs(lessonSecond.getSubjectLongName()) + "</i>";
|
||||
}
|
||||
} else {
|
||||
lessonSecondStr = bs(lessonSecond.getSubjectLongName());
|
||||
}
|
||||
}
|
||||
b.cardTimetableLessonOverview.setText(
|
||||
Html.fromHtml(
|
||||
app.getString(R.string.card_timetable_lesson_overview,
|
||||
lessonFirst.startTime.getStringHM(),
|
||||
bs(null, lessonFirstStr, ", ")+lessonFirst.getClassroomName(),
|
||||
(lessonSecond == null ? "" : lessonSecond.startTime.getStringHM()),
|
||||
(lessonSecond == null ? "" : bs(null, lessonSecondStr, ", "+lessonSecond.getClassroomName())))
|
||||
)
|
||||
);
|
||||
|
||||
StringBuilder eventSummary = new StringBuilder();
|
||||
eventSummary.append(app.getString(R.string.card_timetable_event_overview));
|
||||
for (EventFull event : events) {
|
||||
if (displayingDate.getValue() == event.eventDate.getValue()) {
|
||||
eventSummary.append(app.getString(
|
||||
R.string.card_timetable_event_overview_format,
|
||||
event.startTime == null ? app.getString(R.string.event_all_day) : event.startTime.getStringHM(),
|
||||
event.typeName,
|
||||
event.topic));
|
||||
}
|
||||
}
|
||||
b.cardTimetableEventOverview.setText(eventSummary.toString());
|
||||
}
|
||||
else {
|
||||
b.cardTimetableFullscreenCounter.setVisibility(View.VISIBLE);
|
||||
LessonFull lessonCurrent = null;
|
||||
LessonFull lessonInAMoment = null;
|
||||
LessonFull lessonNext = null;
|
||||
LessonFull lessonAfterNext = null;
|
||||
|
||||
if (lessons.get(notPassedIndex).lessonCurrent) {
|
||||
lessonCurrent = lessons.get(notPassedIndex);
|
||||
if (lessons.size() > notPassedIndex+1 && lessons.get(notPassedIndex+1).weekDay == displayingDate.getWeekDay())
|
||||
lessonNext = lessons.get(notPassedIndex+1);
|
||||
if (lessons.size() > notPassedIndex+2 && lessons.get(notPassedIndex+2).weekDay == displayingDate.getWeekDay())
|
||||
lessonAfterNext = lessons.get(notPassedIndex+2);
|
||||
}
|
||||
else {
|
||||
lessonInAMoment = lessons.get(notPassedIndex);
|
||||
if (lessons.size() > notPassedIndex+1 && lessons.get(notPassedIndex+1).weekDay == displayingDate.getWeekDay())
|
||||
lessonNext = lessons.get(notPassedIndex+1);
|
||||
if (lessons.size() > notPassedIndex+2 && lessons.get(notPassedIndex+2).weekDay == displayingDate.getWeekDay())
|
||||
lessonAfterNext = lessons.get(notPassedIndex+2);
|
||||
}
|
||||
|
||||
if (lessonCurrent != null) { // show time to the end of this lesson
|
||||
b.cardTimetableType.setText(R.string.card_timetable_now);
|
||||
if (lessonCurrent.changeId != 0) {
|
||||
if (lessonCurrent.changeType == TYPE_CANCELLED) {
|
||||
b.cardTimetableSummary.setText(Html.fromHtml("<del>"+bs(lessonCurrent.getSubjectLongName())+"</del><br>"+lessonCurrent.getClassroomName()));
|
||||
}
|
||||
else if (lessonCurrent.changeType == TYPE_CHANGE) {
|
||||
b.cardTimetableSummary.setText(Html.fromHtml("<i>"+bs(lessonCurrent.getSubjectLongName())+"<br>"+lessonCurrent.getClassroomName()+"</i>"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
b.cardTimetableSummary.setText(bs(lessonCurrent.getSubjectLongName())+"\n"+lessonCurrent.getClassroomName());
|
||||
}
|
||||
|
||||
counterTarget = lessonCurrent.endTime;
|
||||
counterType = TIME_LEFT;
|
||||
newRefreshInterval = updateCounter(syncedNow);
|
||||
}
|
||||
else if (lessonInAMoment != null) { // it's break time, show time to the start of next lesson
|
||||
b.cardTimetableType.setText(R.string.card_timetable_following);
|
||||
if (lessonInAMoment.changeId != 0) {
|
||||
if (lessonInAMoment.changeType == TYPE_CANCELLED) {
|
||||
b.cardTimetableSummary.setText(Html.fromHtml("<del>"+bs(lessonInAMoment.getSubjectLongName())+"</del><br>"+lessonInAMoment.getClassroomName()));
|
||||
}
|
||||
else if (lessonInAMoment.changeType == TYPE_CHANGE) {
|
||||
b.cardTimetableSummary.setText(Html.fromHtml("<i>"+bs(lessonInAMoment.getSubjectLongName())+"<br>"+lessonInAMoment.getClassroomName()+"</i>"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
b.cardTimetableSummary.setText(bs(lessonInAMoment.getSubjectLongName())+"\n"+lessonInAMoment.getClassroomName());
|
||||
}
|
||||
|
||||
counterTarget = lessonInAMoment.startTime;
|
||||
counterType = TIME_TILL;
|
||||
newRefreshInterval = updateCounter(syncedNow);
|
||||
}
|
||||
else { // idk what it is now (during lessons, but not during lesson or a break)
|
||||
b.cardTimetableType.setText(R.string.card_timetable_wtf);
|
||||
b.cardTimetableSummary.setText(R.string.card_timetable_wtf_report);
|
||||
b.cardTimetableTimeLeft.setText("");
|
||||
newRefreshInterval = 1000*60*2;
|
||||
}
|
||||
String lessonNextStr = null;
|
||||
if (lessonNext != null) {
|
||||
if (lessonNext.changeId != 0) {
|
||||
if (lessonNext.changeType == TYPE_CANCELLED) {
|
||||
lessonNextStr = "<del>" + lessonNext.getSubjectLongName() + "</del>";
|
||||
} else if (lessonNext.changeType == TYPE_CHANGE) {
|
||||
lessonNextStr = "<i>" + lessonNext.getSubjectLongName() + "</i>";
|
||||
}
|
||||
} else {
|
||||
lessonNextStr = lessonNext.getSubjectLongName();
|
||||
}
|
||||
}
|
||||
String lessonAfterNextStr = null;
|
||||
if (lessonAfterNext != null) {
|
||||
if (lessonAfterNext.changeId != 0) {
|
||||
if (lessonAfterNext.changeType == TYPE_CANCELLED) {
|
||||
lessonAfterNextStr = "<del>" + lessonAfterNext.getSubjectLongName() + "</del>";
|
||||
} else if (lessonAfterNext.changeType == TYPE_CHANGE) {
|
||||
lessonAfterNextStr = "<i>" + lessonAfterNext.getSubjectLongName() + "</i>";
|
||||
}
|
||||
} else {
|
||||
lessonAfterNextStr = lessonAfterNext.getSubjectLongName();
|
||||
}
|
||||
}
|
||||
b.cardTimetableLessonOverview.setText(
|
||||
Html.fromHtml(app.getString(
|
||||
R.string.card_timetable_lesson_overview_ongoing,
|
||||
(lessonNext == null ? "" : lessonNext.startTime.getStringHM()),
|
||||
(lessonNext == null ? "" : bs(null, lessonNextStr, ", "+lessonNext.getClassroomName())),
|
||||
(lessonAfterNext == null ? "" : lessonAfterNext.startTime.getStringHM()),
|
||||
(lessonAfterNext == null ? "" : bs(null, lessonAfterNextStr, ", "+lessonAfterNext.getClassroomName()))
|
||||
))
|
||||
);
|
||||
|
||||
StringBuilder eventSummary = new StringBuilder();
|
||||
eventSummary.append(app.getString(R.string.card_timetable_event_overview));
|
||||
for (EventFull event : events) {
|
||||
// display the event only if it's AllDay or it hasn't started yet
|
||||
boolean timeMatching = event.startTime == null || syncedNow.getValue() < event.startTime.getValue();
|
||||
if (displayingDate.getValue() == event.eventDate.getValue()
|
||||
&& timeMatching) {
|
||||
eventSummary.append(app.getString(
|
||||
R.string.card_timetable_event_overview_format,
|
||||
event.startTime == null ? app.getString(R.string.agenda_event_all_day)+" - " : event.startTime.getStringHM(),
|
||||
event.typeName,
|
||||
event.topic));
|
||||
}
|
||||
}
|
||||
b.cardTimetableEventOverview.setText(eventSummary.toString());
|
||||
}
|
||||
|
||||
b.cardTimetableButton.setOnClickListener((v1 -> new Handler().postDelayed(() -> a.runOnUiThread(() -> {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putInt("timetableDate", displayingDate.getValue());
|
||||
a.loadTarget(MainActivity.DRAWER_ITEM_TIMETABLE, arguments);
|
||||
}), 100)));
|
||||
|
||||
return newRefreshInterval;
|
||||
|
||||
//new Handler().postDelayed(() -> a.runOnUiThread(() -> updateCardTimetable(c, a, root)), newRefreshInterval);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
//Log.d(TAG, "OnDestroy");
|
||||
try {
|
||||
timetableTimer.cancel();
|
||||
timetableTimer.purge();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.homework;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.os.AsyncTask;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
|
||||
public class HomeworkAdapter extends RecyclerView.Adapter<HomeworkAdapter.ViewHolder> {
|
||||
private Context context;
|
||||
private List<EventFull> homeworkList;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public HomeworkAdapter(Context mCtx, List<EventFull> homeworkList) {
|
||||
this.context = mCtx;
|
||||
this.homeworkList = homeworkList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.row_homework_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
public static String dayDiffString(Context context, int dayDiff) {
|
||||
if (dayDiff > 0) {
|
||||
if (dayDiff == 1) {
|
||||
return context.getString(R.string.tomorrow);
|
||||
}
|
||||
else if (dayDiff == 2) {
|
||||
return context.getString(R.string.the_day_after);
|
||||
}
|
||||
return HomeFragment.plural(context, R.plurals.time_till_days, Math.abs(dayDiff));
|
||||
}
|
||||
else if (dayDiff < 0) {
|
||||
if (dayDiff == -1) {
|
||||
return context.getString(R.string.yesterday);
|
||||
}
|
||||
else if (dayDiff == -2) {
|
||||
return context.getString(R.string.the_day_before);
|
||||
}
|
||||
return context.getString(R.string.ago_format, HomeFragment.plural(context, R.plurals.time_till_days, Math.abs(dayDiff)));
|
||||
}
|
||||
return context.getString(R.string.today);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
|
||||
EventFull homework = homeworkList.get(position);
|
||||
|
||||
int diffDays = Date.diffDays(homework.eventDate, Date.getToday());
|
||||
|
||||
holder.homeworkItemHomeworkDate.setText(app.getString(R.string.date_relative_format, homework.eventDate.getFormattedString(), dayDiffString(context, diffDays)));
|
||||
holder.homeworkItemTopic.setText(homework.topic);
|
||||
holder.homeworkItemSubjectTeacher.setText(context.getString(R.string.homework_subject_teacher_format, bs(homework.subjectLongName), bs(homework.teacherFullName)));
|
||||
holder.homeworkItemTeamDate.setText(context.getString(R.string.homework_team_date_format, bs(homework.teamName), Date.fromMillis(homework.addedDate).getFormattedStringShort()));
|
||||
|
||||
if (!homework.seen) {
|
||||
holder.homeworkItemTopic.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
|
||||
holder.homeworkItemTopic.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
homework.seen = true;
|
||||
AsyncTask.execute(() -> {
|
||||
app.db.metadataDao().setSeen(App.profileId, homework, true);
|
||||
});
|
||||
}
|
||||
else {
|
||||
holder.homeworkItemTopic.setBackground(null);
|
||||
}
|
||||
|
||||
holder.homeworkItemEdit.setVisibility((homework.addedManually ? View.VISIBLE : View.GONE));
|
||||
holder.homeworkItemEdit.setOnClickListener(v -> {
|
||||
new EventManualDialog(context).show(app, homework, null, null, EventManualDialog.DIALOG_HOMEWORK);
|
||||
});
|
||||
|
||||
if (homework.sharedBy == null) {
|
||||
holder.homeworkItemSharedBy.setVisibility(View.GONE);
|
||||
}
|
||||
else if (homework.sharedByName != null) {
|
||||
holder.homeworkItemSharedBy.setText(app.getString(R.string.event_shared_by_format, (homework.sharedBy.equals("self") ? app.getString(R.string.event_shared_by_self) : homework.sharedByName)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return homeworkList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
CardView homeworkItemCard;
|
||||
TextView homeworkItemTopic;
|
||||
TextView homeworkItemHomeworkDate;
|
||||
TextView homeworkItemSharedBy;
|
||||
TextView homeworkItemSubjectTeacher;
|
||||
TextView homeworkItemTeamDate;
|
||||
Button homeworkItemEdit;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
homeworkItemCard = itemView.findViewById(R.id.homeworkItemCard);
|
||||
homeworkItemTopic = itemView.findViewById(R.id.homeworkItemTopic);
|
||||
homeworkItemHomeworkDate = itemView.findViewById(R.id.homeworkItemHomeworkDate);
|
||||
homeworkItemSharedBy = itemView.findViewById(R.id.homeworkItemSharedBy);
|
||||
homeworkItemSubjectTeacher = itemView.findViewById(R.id.homeworkItemSubjectTeacher);
|
||||
homeworkItemTeamDate = itemView.findViewById(R.id.homeworkItemTeamDate);
|
||||
homeworkItemEdit = itemView.findViewById(R.id.homeworkItemEdit);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.homework
|
||||
|
||||
class HomeworkDate {
|
||||
companion object {
|
||||
const val CURRENT = 0
|
||||
const val PAST = 1
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.homework
|
||||
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeworkBinding
|
||||
import pl.szczodrzynski.edziennik.datamodels.Metadata
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
|
||||
class HomeworkFragment : Fragment() {
|
||||
companion object {
|
||||
var pageSelection = 0
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentHomeworkBinding
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
activity.bottomSheet.prependItems(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
.withDescription(R.string.menu_add_event_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
EventManualDialog(activity).show(app, null, null, null, EventManualDialog.DIALOG_HOMEWORK)
|
||||
}),
|
||||
BottomSheetSeparatorItem(true),
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, Metadata.TYPE_HOMEWORK, true) }
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
|
||||
}))
|
||||
|
||||
b.viewPager.adapter = MessagesFragment.Adapter(childFragmentManager).also { adapter ->
|
||||
adapter.addFragment(HomeworkListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
args.putInt("homeworkDate", HomeworkDate.CURRENT)
|
||||
}
|
||||
}, getString(R.string.homework_tab_current))
|
||||
|
||||
adapter.addFragment(HomeworkListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
args.putInt("homeworkDate", HomeworkDate.PAST)
|
||||
}
|
||||
}, getString(R.string.homework_tab_past))
|
||||
}
|
||||
|
||||
b.viewPager.currentItem = pageSelection
|
||||
b.viewPager.clearOnPageChangeListeners()
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
}
|
||||
})
|
||||
|
||||
b.tabLayout.setupWithViewPager(b.viewPager)
|
||||
|
||||
activity.navView.bottomBar.fabEnable = true
|
||||
activity.navView.bottomBar.fabExtendedText = getString(R.string.add)
|
||||
activity.navView.bottomBar.fabIcon = CommunityMaterial.Icon2.cmd_plus
|
||||
activity.navView.setFabOnClickListener(View.OnClickListener {
|
||||
EventManualDialog(activity).show(app, null, null, null, EventManualDialog.DIALOG_HOMEWORK)
|
||||
})
|
||||
|
||||
activity.gainAttention()
|
||||
activity.collapseFab()
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.homework
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.HomeworkListBinding
|
||||
import pl.szczodrzynski.edziennik.datamodels.Event
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class HomeworkListFragment : Fragment() {
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: HomeworkListBinding
|
||||
|
||||
private var homeworkDate = HomeworkDate.CURRENT
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = HomeworkListBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
if (arguments != null) {
|
||||
homeworkDate = arguments.getInt("homeworkDate", HomeworkDate.CURRENT)
|
||||
}
|
||||
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
layoutManager.reverseLayout = false
|
||||
layoutManager.stackFromEnd = false
|
||||
|
||||
b.homeworkView.setHasFixedSize(true)
|
||||
b.homeworkView.layoutManager = layoutManager
|
||||
|
||||
val filter = when(homeworkDate) {
|
||||
HomeworkDate.CURRENT -> "eventDate > '" + Date.getToday().stringY_m_d + "'"
|
||||
else -> "eventDate <= '" + Date.getToday().stringY_m_d + "'"
|
||||
}
|
||||
|
||||
app.db.eventDao()
|
||||
.getAllByType(App.profileId, Event.TYPE_HOMEWORK, filter)
|
||||
.observe(this, Observer { homeworkList ->
|
||||
if (app.profile == null || !isAdded) return@Observer
|
||||
|
||||
if (homeworkList != null && homeworkList.size > 0) {
|
||||
val adapter = HomeworkAdapter(context, homeworkList)
|
||||
b.homeworkView.adapter = adapter
|
||||
b.homeworkView.visibility = View.VISIBLE
|
||||
b.homeworkNoData.visibility = View.GONE
|
||||
} else {
|
||||
b.homeworkView.visibility = View.GONE
|
||||
b.homeworkNoData.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.intro;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.heinrichreimersoftware.materialintro.app.IntroActivity;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class ChangelogIntroActivity extends IntroActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
App app = (App)getApplication();
|
||||
overridePendingTransition(R.anim.fade_in, 0);
|
||||
super.onCreate(savedInstanceState);
|
||||
setButtonBackVisible(true);
|
||||
setButtonBackFunction(BUTTON_BACK_FUNCTION_BACK);
|
||||
setButtonNextVisible(true);
|
||||
setButtonNextFunction(BUTTON_NEXT_FUNCTION_NEXT_FINISH);
|
||||
setButtonCtaVisible(false);
|
||||
setPageScrollDuration(500);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setPageScrollInterpolator(android.R.interpolator.fast_out_slow_in);
|
||||
}
|
||||
|
||||
/*if (app.appConfig.lastAppVersion < 120) {
|
||||
addSlide(new SimpleSlide.Builder()
|
||||
.title(R.string.intro_web_push_title)
|
||||
.description(R.string.intro_web_push_text)
|
||||
.image(R.drawable.intro_web_push)
|
||||
.background(R.color.introPage5Color)
|
||||
.backgroundDark(R.color.introPage5ColorDark)
|
||||
.buttonCtaLabel(R.string.ok)
|
||||
.buttonCtaClickListener(v -> nextSlide())
|
||||
.scrollable(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
if (app.appConfig.lastAppVersion < 141) {
|
||||
addSlide(new SimpleSlide.Builder()
|
||||
.title(R.string.intro_grades_editor_title)
|
||||
.description(R.string.intro_grades_editor_text)
|
||||
.image(R.drawable.intro_grades_editor)
|
||||
.background(R.color.introPage5Color)
|
||||
.backgroundDark(R.color.introPage5ColorDark)
|
||||
.buttonCtaLabel(R.string.ok)
|
||||
.buttonCtaClickListener(v -> nextSlide())
|
||||
.scrollable(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
if (app.appConfig.lastAppVersion < 150) {
|
||||
addSlide(new SimpleSlide.Builder()
|
||||
.title(R.string.intro_manual_events_title)
|
||||
.description(R.string.intro_manual_events_text)
|
||||
.image(R.drawable.intro_manual_events)
|
||||
.background(R.color.introPage5Color)
|
||||
.backgroundDark(R.color.introPage5ColorDark)
|
||||
.buttonCtaLabel(R.string.ok)
|
||||
.buttonCtaClickListener(v -> nextSlide())
|
||||
.scrollable(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
if (app.appConfig.lastAppVersion < 170) {
|
||||
addSlide(new SimpleSlide.Builder()
|
||||
.title(R.string.intro_synergia_title)
|
||||
.description(R.string.intro_synergia_text)
|
||||
.image(R.drawable.intro_synergia)
|
||||
.background(R.color.introPage5Color)
|
||||
.backgroundDark(R.color.introPage5ColorDark)
|
||||
.buttonCtaLabel(R.string.ok)
|
||||
.buttonCtaClickListener(v -> nextSlide())
|
||||
.scrollable(true)
|
||||
.build());
|
||||
}*/
|
||||
|
||||
app.appConfig.lastAppVersion = BuildConfig.VERSION_CODE;
|
||||
app.appConfig.savePending = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017 Jan Heinrich Reimer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.intro;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.heinrichreimersoftware.materialintro.app.ButtonCtaFragment;
|
||||
import com.heinrichreimersoftware.materialintro.app.SlideFragment;
|
||||
import com.heinrichreimersoftware.materialintro.slide.ButtonCtaSlide;
|
||||
import com.heinrichreimersoftware.materialintro.slide.RestorableSlide;
|
||||
import com.heinrichreimersoftware.materialintro.slide.Slide;
|
||||
import com.heinrichreimersoftware.materialintro.view.parallax.ParallaxFragment;
|
||||
|
||||
public class FragmentSlideMod implements Slide, RestorableSlide, ButtonCtaSlide {
|
||||
|
||||
private Fragment fragment;
|
||||
@ColorRes
|
||||
public int background;
|
||||
@ColorRes
|
||||
private final int backgroundDark;
|
||||
private final boolean canGoForward;
|
||||
private final boolean canGoBackward;
|
||||
private CharSequence buttonCtaLabel = null;
|
||||
@StringRes
|
||||
private int buttonCtaLabelRes = 0;
|
||||
private View.OnClickListener buttonCtaClickListener = null;
|
||||
|
||||
protected FragmentSlideMod(Builder builder) {
|
||||
fragment = builder.fragment;
|
||||
background = builder.background;
|
||||
backgroundDark = builder.backgroundDark;
|
||||
canGoForward = builder.canGoForward;
|
||||
canGoBackward = builder.canGoBackward;
|
||||
buttonCtaLabel = builder.buttonCtaLabel;
|
||||
buttonCtaLabelRes = builder.buttonCtaLabelRes;
|
||||
buttonCtaClickListener = builder.buttonCtaClickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getFragment() {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFragment(Fragment fragment) {
|
||||
this.fragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBackgroundDark() {
|
||||
return backgroundDark;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canGoForward() {
|
||||
if (getFragment() instanceof SlideFragment) {
|
||||
return ((SlideFragment) getFragment()).canGoForward();
|
||||
}
|
||||
return canGoForward;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canGoBackward() {
|
||||
if (getFragment() instanceof SlideFragment) {
|
||||
return ((SlideFragment) getFragment()).canGoBackward();
|
||||
}
|
||||
return canGoBackward;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View.OnClickListener getButtonCtaClickListener() {
|
||||
if (getFragment() instanceof ButtonCtaFragment) {
|
||||
return ((ButtonCtaFragment) getFragment()).getButtonCtaClickListener();
|
||||
}
|
||||
return buttonCtaClickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getButtonCtaLabel() {
|
||||
if (getFragment() instanceof ButtonCtaFragment) {
|
||||
return ((ButtonCtaFragment) getFragment()).getButtonCtaLabel();
|
||||
}
|
||||
return buttonCtaLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButtonCtaLabelRes() {
|
||||
if (getFragment() instanceof ButtonCtaFragment) {
|
||||
return ((ButtonCtaFragment) getFragment()).getButtonCtaLabelRes();
|
||||
}
|
||||
return buttonCtaLabelRes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FragmentSlideMod that = (FragmentSlideMod) o;
|
||||
|
||||
if (background != that.background) return false;
|
||||
if (backgroundDark != that.backgroundDark) return false;
|
||||
if (canGoForward != that.canGoForward) return false;
|
||||
if (canGoBackward != that.canGoBackward) return false;
|
||||
if (buttonCtaLabelRes != that.buttonCtaLabelRes) return false;
|
||||
if (fragment != null ? !fragment.equals(that.fragment) : that.fragment != null)
|
||||
return false;
|
||||
if (buttonCtaLabel != null ? !buttonCtaLabel.equals(that.buttonCtaLabel) : that.buttonCtaLabel != null)
|
||||
return false;
|
||||
return buttonCtaClickListener != null ? buttonCtaClickListener.equals(that.buttonCtaClickListener) : that.buttonCtaClickListener == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = fragment != null ? fragment.hashCode() : 0;
|
||||
result = 31 * result + background;
|
||||
result = 31 * result + backgroundDark;
|
||||
result = 31 * result + (canGoForward ? 1 : 0);
|
||||
result = 31 * result + (canGoBackward ? 1 : 0);
|
||||
result = 31 * result + (buttonCtaLabel != null ? buttonCtaLabel.hashCode() : 0);
|
||||
result = 31 * result + buttonCtaLabelRes;
|
||||
result = 31 * result + (buttonCtaClickListener != null ? buttonCtaClickListener.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Fragment fragment;
|
||||
@ColorRes
|
||||
private int background;
|
||||
@ColorRes
|
||||
private int backgroundDark = 0;
|
||||
private boolean canGoForward = true;
|
||||
private boolean canGoBackward = true;
|
||||
private CharSequence buttonCtaLabel = null;
|
||||
@StringRes
|
||||
private int buttonCtaLabelRes = 0;
|
||||
private View.OnClickListener buttonCtaClickListener = null;
|
||||
|
||||
public Builder fragment(Fragment fragment) {
|
||||
this.fragment = fragment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fragment(@LayoutRes int layoutRes, @StyleRes int themeRes) {
|
||||
this.fragment = FragmentSlideFragment.newInstance(layoutRes, themeRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fragment(@LayoutRes int layoutRes) {
|
||||
this.fragment = FragmentSlideFragment.newInstance(layoutRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder background(@ColorRes int background) {
|
||||
this.background = background;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder backgroundDark(@ColorRes int backgroundDark) {
|
||||
this.backgroundDark = backgroundDark;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder canGoForward(boolean canGoForward) {
|
||||
this.canGoForward = canGoForward;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder canGoBackward(boolean canGoBackward) {
|
||||
this.canGoBackward = canGoBackward;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder buttonCtaLabel(CharSequence buttonCtaLabel) {
|
||||
this.buttonCtaLabel = buttonCtaLabel;
|
||||
this.buttonCtaLabelRes = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder buttonCtaLabelHtml(String buttonCtaLabelHtml) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
this.buttonCtaLabel = Html.fromHtml(buttonCtaLabelHtml, Html.FROM_HTML_MODE_LEGACY);
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
this.buttonCtaLabel = Html.fromHtml(buttonCtaLabelHtml);
|
||||
}
|
||||
this.buttonCtaLabelRes = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder buttonCtaLabel(@StringRes int buttonCtaLabelRes) {
|
||||
this.buttonCtaLabelRes = buttonCtaLabelRes;
|
||||
this.buttonCtaLabel = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder buttonCtaClickListener(View.OnClickListener buttonCtaClickListener) {
|
||||
this.buttonCtaClickListener = buttonCtaClickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FragmentSlideMod build() {
|
||||
if (background == 0 || fragment == null)
|
||||
throw new IllegalArgumentException("You must set at least a fragment and background.");
|
||||
return new FragmentSlideMod(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FragmentSlideFragment extends ParallaxFragment {
|
||||
private static final String ARGUMENT_LAYOUT_RES =
|
||||
"com.heinrichreimersoftware.materialintro.SimpleFragment.ARGUMENT_LAYOUT_RES";
|
||||
private static final String ARGUMENT_THEME_RES =
|
||||
"com.heinrichreimersoftware.materialintro.SimpleFragment.ARGUMENT_THEME_RES";
|
||||
|
||||
public FragmentSlideFragment() {
|
||||
}
|
||||
|
||||
public static FragmentSlideFragment newInstance(@LayoutRes int layoutRes, @StyleRes int themeRes) {
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putInt(ARGUMENT_LAYOUT_RES, layoutRes);
|
||||
arguments.putInt(ARGUMENT_THEME_RES, themeRes);
|
||||
|
||||
FragmentSlideFragment fragment = new FragmentSlideFragment();
|
||||
fragment.setArguments(arguments);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static FragmentSlideFragment newInstance(@LayoutRes int layoutRes) {
|
||||
return newInstance(layoutRes, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
int themeRes = getArguments().getInt(ARGUMENT_THEME_RES);
|
||||
Context contextThemeWrapper;
|
||||
if (themeRes != 0) {
|
||||
contextThemeWrapper = new ContextThemeWrapper(getActivity(), themeRes);
|
||||
} else {
|
||||
contextThemeWrapper = getActivity();
|
||||
}
|
||||
LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
|
||||
|
||||
return localInflater.inflate(getArguments().getInt(ARGUMENT_LAYOUT_RES), container, false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.navigation.NavDestination;
|
||||
import androidx.navigation.NavOptions;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityLoginBinding;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityLoginBinding b;
|
||||
private App app;
|
||||
private static final String TAG = "LoginActivity";
|
||||
public static final int RESULT_OK = 1;
|
||||
public static NavOptions navOptions;
|
||||
|
||||
static AppError error = null;
|
||||
|
||||
static List<LoginProfileObject> profileObjects;
|
||||
public static boolean firstCompleted = false; // if a profile is already added during *this* login. This means that LoginChooser has to navigateUp onBackPressed. Else, finish the activity.
|
||||
public static boolean privacyPolicyAccepted = false;
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
NavDestination destination = Navigation.findNavController(this, R.id.nav_host_fragment).getCurrentDestination();
|
||||
if (destination != null && destination.getId() == R.id.loginMigrationFragment) {
|
||||
return;
|
||||
}
|
||||
if (destination != null && destination.getId() == R.id.loginMigrationSyncFragment) {
|
||||
return;
|
||||
}
|
||||
if (destination != null && destination.getId() == R.id.loginSyncErrorFragment) {
|
||||
return;
|
||||
}
|
||||
if (destination != null && destination.getId() == R.id.loginProgressFragment) {
|
||||
return;
|
||||
}
|
||||
if (destination != null && destination.getId() == R.id.loginSyncFragment) {
|
||||
return;
|
||||
}
|
||||
if (destination != null && destination.getId() == R.id.loginChooserFragment && !firstCompleted) {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
if (destination != null && destination.getId() == R.id.loginSummaryFragment) {
|
||||
new MaterialDialog.Builder(this)
|
||||
.title(R.string.are_you_sure)
|
||||
.content(R.string.login_cancel_confirmation)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive((dialog, which) -> {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
})
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
firstCompleted = false;
|
||||
profileObjects = new ArrayList<>();
|
||||
error = null;
|
||||
|
||||
navOptions = new NavOptions.Builder()
|
||||
.setEnterAnim(R.anim.slide_in_right)
|
||||
.setExitAnim(R.anim.slide_out_left)
|
||||
.setPopEnterAnim(R.anim.slide_in_left)
|
||||
.setPopExitAnim(R.anim.slide_out_right)
|
||||
.build();
|
||||
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_login, null, false);
|
||||
setContentView(b.getRoot());
|
||||
|
||||
app = (App) getApplication();
|
||||
|
||||
if (!app.appConfig.loginFinished) {
|
||||
app.appConfig.miniDrawerVisible = getResources().getConfiguration().smallestScreenWidthDp > 480;
|
||||
app.saveConfig("miniDrawerVisible");
|
||||
}
|
||||
|
||||
/*b.getRoot().addOnLayoutChangeListener(((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
Animator circularReveal = null;
|
||||
float finalRadius = (float) (Math.max(b.revealView.getWidth(), b.revealView.getHeight()) * 1.1);
|
||||
circularReveal = ViewAnimationUtils.createCircularReveal(b.revealView, b.revealView.getWidth()/2, b.revealView.getHeight()/2, 0, finalRadius);
|
||||
circularReveal.setDuration(400);
|
||||
circularReveal.setInterpolator(new AccelerateInterpolator());
|
||||
// make the view visible and start the animation
|
||||
b.revealView.setVisibility(View.VISIBLE);
|
||||
circularReveal.addListener(new Animator.AnimatorListener() {
|
||||
@Override public void onAnimationEnd(Animator animation) {
|
||||
Anim.fadeIn(b.title1, 500, new Animation.AnimationListener() {
|
||||
@Override public void onAnimationEnd(Animation animation) {
|
||||
b.title2.postDelayed(() -> {
|
||||
Anim.fadeIn(b.title2, 500, new Animation.AnimationListener() {
|
||||
@Override public void onAnimationEnd(Animation animation) {
|
||||
b.revealView.postDelayed(() -> {
|
||||
Anim.fadeOut(b.title1, 500, null);
|
||||
Animation anim2 = null;
|
||||
anim2 = new Anim.ResizeAnimation(b.revealView, 1.0f, 1.0f, 1.0f, 0.15f);
|
||||
anim2.setDuration(800);
|
||||
anim2.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
b.revealView.startAnimation(anim2);
|
||||
}, 700);
|
||||
}
|
||||
@Override public void onAnimationStart(Animation animation) { }
|
||||
@Override public void onAnimationRepeat(Animation animation) { }
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
@Override public void onAnimationStart(Animation animation) { }
|
||||
@Override public void onAnimationRepeat(Animation animation) { }
|
||||
});
|
||||
}
|
||||
@Override public void onAnimationCancel(Animator animation) { }
|
||||
@Override public void onAnimationStart(Animator animation) { }
|
||||
@Override public void onAnimationRepeat(Animator animation) { }
|
||||
});
|
||||
circularReveal.start();
|
||||
}));*/
|
||||
|
||||
/**/
|
||||
|
||||
/*TextInputEditText e = findViewById(R.id.buttontest);
|
||||
|
||||
e.setOnClickListener((v -> {
|
||||
Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show();
|
||||
PopupMenu popup = new PopupMenu(this, e);
|
||||
//popup.getMenu().add(0, 15, 0, HomeFragment.plural(c, R.plurals.time_till_seconds, 15));
|
||||
//popup.getMenu().add(0, 15 * 60, 0, HomeFragment.plural(c, R.plurals.time_till_minutes, 15));
|
||||
popup.getMenu().add(0, 30 * 60, 0, HomeFragment.plural(this, R.plurals.time_till_minutes, 30));
|
||||
popup.getMenu().add(0, 60 * 60, 0, HomeFragment.plural(this, R.plurals.time_till_hours, 1));
|
||||
popup.getMenu().add(0, 120 * 60, 0, HomeFragment.plural(this, R.plurals.time_till_hours, 2));
|
||||
popup.getMenu().add(0, 180 * 60, 0, HomeFragment.plural(this, R.plurals.time_till_hours, 3));
|
||||
popup.getMenu().add(0, 240 * 60, 0, HomeFragment.plural(this, R.plurals.time_till_hours, 4));
|
||||
popup.setOnMenuItemClickListener(item -> {
|
||||
e.setText(item.getTitle());
|
||||
return false;
|
||||
});
|
||||
popup.show();
|
||||
}));*/
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.FeedbackActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginChooserBinding;
|
||||
|
||||
import static android.app.Activity.RESULT_CANCELED;
|
||||
|
||||
public class LoginChooserFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginChooserBinding b;
|
||||
private static final String TAG = "LoginTemplate";
|
||||
|
||||
public LoginChooserFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_chooser, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.loginMobidziennikLogo.setOnClickListener((v) -> nav.navigate(R.id.loginMobidziennikFragment, null, LoginActivity.navOptions));
|
||||
b.loginLibrusLogo.setOnClickListener((v) -> nav.navigate(R.id.loginLibrusFragment, null, LoginActivity.navOptions));
|
||||
b.loginVulcanLogo.setOnClickListener((v) -> nav.navigate(R.id.loginVulcanFragment, null, LoginActivity.navOptions));
|
||||
b.loginIuczniowieLogo.setOnClickListener((v) -> nav.navigate(R.id.loginIuczniowieFragment, null, LoginActivity.navOptions));
|
||||
|
||||
if (LoginActivity.firstCompleted) {
|
||||
// we are navigated here from LoginSummary
|
||||
b.cancelButton.setVisibility(View.VISIBLE);
|
||||
b.cancelButton.setOnClickListener((v -> nav.navigateUp()));
|
||||
}
|
||||
else if (app.appConfig.lastAppVersion < 1991) {
|
||||
nav.navigate(R.id.loginMigrationFragment, null, LoginActivity.navOptions);
|
||||
}
|
||||
else if (app.appConfig.loginFinished) {
|
||||
// we are navigated here from AppDrawer
|
||||
b.cancelButton.setVisibility(View.VISIBLE);
|
||||
b.cancelButton.setOnClickListener((v -> {
|
||||
getActivity().setResult(RESULT_CANCELED);
|
||||
getActivity().finish();
|
||||
}));
|
||||
}
|
||||
else {
|
||||
// there is no profiles
|
||||
b.cancelButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
b.helpButton.setOnClickListener((v -> {
|
||||
startActivity(new Intent(getActivity(), FeedbackActivity.class));
|
||||
}));
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginFinishBinding;
|
||||
|
||||
public class LoginFinishFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginFinishBinding b;
|
||||
private static final String TAG = "LoginFinishFragment";
|
||||
static boolean firstRun = true;
|
||||
static int firstProfileId = -1;
|
||||
|
||||
public LoginFinishFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_finish, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
if (!firstRun) {
|
||||
b.loginFinishSubtitle.setText(R.string.login_finish_subtitle_not_first_run);
|
||||
}
|
||||
|
||||
b.finishButton.setOnClickListener((v -> {
|
||||
Intent intent = null;
|
||||
if (firstProfileId != -1) {
|
||||
intent = new Intent();
|
||||
intent.putExtra("profileId", firstProfileId);
|
||||
intent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOME);
|
||||
}
|
||||
getActivity().setResult(Activity.RESULT_OK, intent);
|
||||
getActivity().finish();
|
||||
}));
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieBinding;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_LOGIN;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_SCHOOL_NAME;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_IUCZNIOWIE;
|
||||
|
||||
public class LoginIuczniowieFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginIuczniowieBinding b;
|
||||
private static final String TAG = "LoginIuczniowie";
|
||||
|
||||
public LoginIuczniowieFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_iuczniowie, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
case CODE_INVALID_SCHOOL_NAME:
|
||||
b.loginSchoolNameLayout.setError(getString(R.string.login_error_incorrect_school_name));
|
||||
break;
|
||||
case CODE_INVALID_LOGIN:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
b.helpButton.setOnClickListener((v) -> nav.navigate(R.id.loginIuczniowieHelpFragment, null, LoginActivity.navOptions));
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
|
||||
b.loginButton.setOnClickListener((v) -> {
|
||||
boolean errors = false;
|
||||
|
||||
b.loginSchoolNameLayout.setError(null);
|
||||
b.loginUsernameLayout.setError(null);
|
||||
b.loginPasswordLayout.setError(null);
|
||||
|
||||
Editable schoolNameEditable = b.loginSchoolName.getText();
|
||||
Editable usernameEditable = b.loginUsername.getText();
|
||||
Editable passwordEditable = b.loginPassword.getText();
|
||||
if (schoolNameEditable == null || schoolNameEditable.length() == 0) {
|
||||
b.loginSchoolNameLayout.setError(getString(R.string.login_error_no_school_name));
|
||||
errors = true;
|
||||
}
|
||||
if (usernameEditable == null || usernameEditable.length() == 0) {
|
||||
b.loginUsernameLayout.setError(getString(R.string.login_error_no_username));
|
||||
errors = true;
|
||||
}
|
||||
if (passwordEditable == null || passwordEditable.length() == 0) {
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_no_password));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
String schoolName = schoolNameEditable.toString().toLowerCase();
|
||||
String username = usernameEditable.toString().toLowerCase();
|
||||
String password = passwordEditable.toString();
|
||||
b.loginSchoolName.setText(schoolName);
|
||||
b.loginUsername.setText(username);
|
||||
if (!schoolName.matches("[a-z0-9_\\-]+")) {
|
||||
b.loginSchoolNameLayout.setError(getString(R.string.login_error_incorrect_school_name));
|
||||
errors = true;
|
||||
}
|
||||
if (!username.matches("[a-z0-9_\\-]+")) {
|
||||
b.loginUsernameLayout.setError(getString(R.string.login_error_incorrect_username));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("loginType", LOGIN_TYPE_IUCZNIOWIE);
|
||||
args.putString("schoolName", schoolName);
|
||||
args.putString("username", username);
|
||||
args.putString("password", password);
|
||||
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieHelpBinding;
|
||||
|
||||
public class LoginIuczniowieHelpFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginIuczniowieHelpBinding b;
|
||||
private static final String TAG = "LoginIuczniowieHelp";
|
||||
|
||||
public LoginIuczniowieHelpFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_iuczniowie_help, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusBinding;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_LOGIN;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_LIBRUS_NOT_ACTIVATED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
|
||||
public class LoginLibrusFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginLibrusBinding b;
|
||||
private static final String TAG = "LoginLibrus";
|
||||
|
||||
public LoginLibrusFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_librus, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
case CODE_INVALID_LOGIN:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
case CODE_LIBRUS_NOT_ACTIVATED:
|
||||
b.loginEmailLayout.setError(getString(R.string.login_error_account_not_activated));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.duration(10000)
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
b.helpButton.setOnClickListener((v) -> nav.navigate(R.id.loginLibrusHelpFragment, null, LoginActivity.navOptions));
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
|
||||
b.loginButton.setOnClickListener((v) -> {
|
||||
boolean errors = false;
|
||||
|
||||
b.loginEmailLayout.setError(null);
|
||||
b.loginPasswordLayout.setError(null);
|
||||
|
||||
Editable emailEditable = b.loginEmail.getText();
|
||||
Editable passwordEditable = b.loginPassword.getText();
|
||||
if (emailEditable == null || emailEditable.length() == 0) {
|
||||
b.loginEmailLayout.setError(getString(R.string.login_error_no_email));
|
||||
errors = true;
|
||||
}
|
||||
if (passwordEditable == null || passwordEditable.length() == 0) {
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_no_password));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
String email = emailEditable.toString().toLowerCase();
|
||||
String password = passwordEditable.toString();
|
||||
b.loginEmail.setText(email);
|
||||
if (!email.matches("([\\w.\\-_+]+)?\\w+@[\\w-_]+(\\.\\w+)+")) {
|
||||
b.loginEmailLayout.setError(getString(R.string.login_error_incorrect_email));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("loginType", LOGIN_TYPE_LIBRUS);
|
||||
args.putString("email", email);
|
||||
args.putString("password", password);
|
||||
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusHelpBinding;
|
||||
|
||||
public class LoginLibrusHelpFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginLibrusHelpBinding b;
|
||||
private static final String TAG = "LoginLibrusHelp";
|
||||
|
||||
public LoginLibrusHelpFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_librus_help, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
}
|
||||
}
|
@ -0,0 +1,638 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMigrationBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Attendance;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Event;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventType;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Grade;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Lesson;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonChange;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LuckyNumber;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Metadata;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Notice;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Subject;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Teacher;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Team;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
import android.util.LongSparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_CLASS_EVENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_DEFAULT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_ESSAY;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_EXAM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_EXCURSION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_INFORMATION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_PROJECT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_PT_MEETING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_READING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_SHORT_QUIZ;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_CLASS_EVENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_DEFAULT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_ESSAY;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_EXAM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_EXCURSION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_INFORMATION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_PROJECT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_PT_MEETING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_READING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_SHORT_QUIZ;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_DEMO;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_IUCZNIOWIE;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_VULCAN;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_DISABLED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_ENABLED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_UNSPECIFIED;
|
||||
|
||||
public class LoginMigrationFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginMigrationBinding b;
|
||||
private static final String TAG = "LoginMigration";
|
||||
|
||||
public LoginMigrationFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_migration, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
String profilesStr;
|
||||
if (app.appConfig.lastAppVersion == 198 && (profilesStr = app.appSharedPrefs.getString("app.appConfig.profiles", null)) != null) {
|
||||
Toast.makeText(app, getString(R.string.login_migration_toast), Toast.LENGTH_SHORT).show();
|
||||
AsyncTask.execute(() -> {
|
||||
try {
|
||||
migrate(profilesStr);
|
||||
}
|
||||
catch (Exception e) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.error_occured)
|
||||
.content(getString(R.string.login_migration_error_format))
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(((dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
}))
|
||||
.autoDismiss(false)
|
||||
.canceledOnTouchOutside(false)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
finally {
|
||||
if (app.db.profileDao().getIdsNow().size() != 0) {
|
||||
app.appSharedPrefs.edit().remove("app.appConfig.profiles").apply();
|
||||
}
|
||||
app.appConfig.lastAppVersion = BuildConfig.VERSION_CODE;
|
||||
app.saveConfig("lastAppVersion");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.doneButton.setOnClickListener((v -> {
|
||||
nav.navigate(R.id.loginMigrationSyncFragment, null, LoginActivity.navOptions);
|
||||
}));
|
||||
}
|
||||
|
||||
private String gp(SharedPreferences p, String key, String defValue) {
|
||||
String s = p.getString(key, defValue);
|
||||
if (s == null)
|
||||
s = defValue;
|
||||
return s;
|
||||
}
|
||||
private void migrate(String profilesStr) {
|
||||
Context c = getContext();
|
||||
if (c == null)
|
||||
return;
|
||||
List<Metadata> metadataList = new ArrayList<>();
|
||||
JsonArray profiles = new JsonParser().parse(profilesStr).getAsJsonArray();
|
||||
Map<Integer, JsonObject> loginStores = app.gson.fromJson(app.appSharedPrefs.getString("app.appConfig.loginStores", "{}"), new TypeToken<Map<Integer, JsonObject>>(){}.getType());
|
||||
if (loginStores == null) {
|
||||
Toast.makeText(c, "Błąd odczytywania słoików z danymi.", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
for (JsonElement profileEl: profiles) {
|
||||
JsonObject jProfile = profileEl.getAsJsonObject();
|
||||
int profileId = jProfile.get("id").getAsInt();
|
||||
SharedPreferences p = app.getSharedPreferences(String.format(getString(R.string.preference_file_register), profileId), Context.MODE_PRIVATE);
|
||||
|
||||
if (!Boolean.parseBoolean(p.getString("app.register.loggedIn", Boolean.toString(false))))
|
||||
return;
|
||||
Profile profile = new Profile();
|
||||
profile.setId(profileId);
|
||||
profile.setName(jProfile.get("name").getAsString());
|
||||
profile.setSubname(jProfile.get("subname").getAsString());
|
||||
profile.setImage(jProfile.get("image").getAsString());
|
||||
|
||||
profile.setSyncEnabled(Boolean.parseBoolean(p.getString("app.register.syncThisProfile", Boolean.toString(profile.getSyncEnabled()))));
|
||||
profile.setSyncNotifications(Boolean.parseBoolean(p.getString("app.register.syncNotificationsEnabled", Boolean.toString(profile.getSyncNotifications()))));
|
||||
profile.setEnableSharedEvents(Boolean.parseBoolean(p.getString("app.register.eventsShared", Boolean.toString(profile.getEnableSharedEvents()))));
|
||||
app.appConfig.countInSeconds = Boolean.parseBoolean(p.getString("app.register.countInSeconds", Boolean.toString(app.appConfig.countInSeconds)));
|
||||
profile.setLoggedIn(true);
|
||||
// so in some APIs we force a full, clean sync
|
||||
profile.setEmpty(true);//Boolean.parseBoolean(p.getString("app.register.empty", Boolean.toString(profile.empty)));
|
||||
profile.setArchived(false);
|
||||
|
||||
String s;
|
||||
s = gp(p, "app.register.studentNameLong", "\"\"");
|
||||
profile.setStudentNameLong(s.replace("\"", ""));
|
||||
s = gp(p, "app.register.studentNameShort", "\"\"");
|
||||
profile.setStudentNameShort(s.replace("\"", ""));
|
||||
profile.setStudentNumber(Integer.parseInt(gp(p, "app.register.studentNumber", "-1")));
|
||||
profile.setStudentData(new JsonParser().parse(gp(p, "app.register.studentStore", "[]")).getAsJsonObject());
|
||||
|
||||
boolean autoRegistrationDecided = Boolean.parseBoolean(p.getString("app.register.autoRegistrationDecided", "true"));
|
||||
boolean autoRegistrationAllowed = Boolean.parseBoolean(p.getString("app.register.autoRegistrationAllowed", "true"));
|
||||
profile.setRegistration(!autoRegistrationAllowed && !autoRegistrationDecided ? REGISTRATION_UNSPECIFIED : !autoRegistrationAllowed ? REGISTRATION_DISABLED : REGISTRATION_ENABLED);
|
||||
|
||||
profile.setGradeColorMode(Integer.parseInt(gp(p, "app.register.gradeColorMode", "1")));
|
||||
profile.setAgendaViewType(Integer.parseInt(gp(p, "app.register.agendaViewType", "0")));
|
||||
|
||||
profile.setCurrentSemester(Integer.parseInt(gp(p, "app.register.currentSemester", "1")));
|
||||
|
||||
profile.setAttendancePercentage(Float.parseFloat(gp(p, "app.register.attendancePercentage", "0.0")));
|
||||
|
||||
profile.setDateSemester1Start(app.gson.fromJson(gp(p, "app.register.dateSemester1Start", ""), Date.class));
|
||||
profile.setDateSemester2Start(app.gson.fromJson(gp(p, "app.register.dateSemester2Start", ""), Date.class));
|
||||
profile.setDateYearEnd(app.gson.fromJson(gp(p, "app.register.dateYearEnd", ""), Date.class));
|
||||
|
||||
profile.setLuckyNumberEnabled(Boolean.parseBoolean(gp(p, "app.register.luckyNumberEnabled", Boolean.toString(profile.getLuckyNumberEnabled()))));
|
||||
profile.setLuckyNumber(Integer.parseInt(gp(p, "app.register.luckyNumber", "-1")));
|
||||
profile.setLuckyNumberDate(app.gson.fromJson(gp(p, "app.register.luckyNumberDate", ""), Date.class));
|
||||
|
||||
|
||||
profile.setLoginStoreId(jProfile.get("loginStoreId").getAsInt());
|
||||
|
||||
|
||||
|
||||
LoginStore loginStore = new LoginStore(
|
||||
profile.getLoginStoreId(),
|
||||
Integer.parseInt(gp(p, "app.register.loginType", "1")),
|
||||
loginStores.get(profile.getLoginStoreId())
|
||||
);
|
||||
|
||||
String teamPrefix;
|
||||
switch (loginStore.type) {
|
||||
case LOGIN_TYPE_MOBIDZIENNIK:
|
||||
teamPrefix = loginStore.getLoginData("serverName", "MOBI_UN");
|
||||
break;
|
||||
case LOGIN_TYPE_LIBRUS:
|
||||
teamPrefix = profile.getStudentData("schoolName", "LIBRUS_UN");
|
||||
break;
|
||||
case LOGIN_TYPE_IUCZNIOWIE:
|
||||
teamPrefix = loginStore.getLoginData("schoolName", "IUCZNIOWIE_UN");
|
||||
break;
|
||||
case LOGIN_TYPE_VULCAN:
|
||||
teamPrefix = profile.getStudentData("schoolName", "VULCAN_UN");
|
||||
break;
|
||||
case LOGIN_TYPE_DEMO:
|
||||
teamPrefix = loginStore.getLoginData("serverName", "DEMO_UN");
|
||||
break;
|
||||
default:
|
||||
teamPrefix = "TYPE_UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
JsonArray items = new JsonParser().parse(gp(p, "app.register.users", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Teacher> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
if (item.get("id").getAsLong() == -1)
|
||||
continue;
|
||||
itemList.add(new Teacher(
|
||||
profileId,
|
||||
item.get("id").getAsLong() + (loginStore.type == LOGIN_TYPE_IUCZNIOWIE ? 32768 : 0),
|
||||
item.get("name").getAsString(),
|
||||
item.get("surname").getAsString()
|
||||
));
|
||||
}
|
||||
app.db.teacherDao().addAllIgnore(itemList);
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.subjects", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Subject> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
if (item.get("id").getAsLong() == -1)
|
||||
continue;
|
||||
itemList.add(new Subject(
|
||||
profileId,
|
||||
item.get("id").getAsLong() + (loginStore.type == LOGIN_TYPE_IUCZNIOWIE ? 32768 : 0),
|
||||
item.get("longName").getAsString(),
|
||||
item.get("shortName").getAsString()
|
||||
));
|
||||
}
|
||||
app.db.subjectDao().addAll(itemList);
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.teams", "[]")).getAsJsonArray();
|
||||
List<Team> tItemList = new ArrayList<>();
|
||||
if (items != null) {
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
if (item.get("id").getAsLong() == -1)
|
||||
continue;
|
||||
tItemList.add(new Team(
|
||||
profileId,
|
||||
item.get("id").getAsLong() + (loginStore.type == LOGIN_TYPE_IUCZNIOWIE ? 32768 : 0),
|
||||
item.get("name").getAsString(),
|
||||
item.get("type").getAsInt(),
|
||||
teamPrefix+":"+item.get("name").getAsString(),
|
||||
item.get("teacherId").getAsInt()
|
||||
));
|
||||
}
|
||||
}
|
||||
JsonObject tItem = new JsonParser().parse(gp(p, "app.register.teamClass", "")).getAsJsonObject();
|
||||
tItemList.add(new Team(
|
||||
profileId,
|
||||
tItem.get("id").getAsLong(),
|
||||
tItem.get("name").getAsString(),
|
||||
tItem.get("type").getAsInt(),
|
||||
teamPrefix+":"+tItem.get("name").getAsString(),
|
||||
tItem.get("teacherId").getAsInt()
|
||||
));
|
||||
app.db.teamDao().addAll(tItemList);
|
||||
|
||||
Map<Integer, Pair<String, Integer>> types = app.gson.fromJson(p.getString("app.register.eventTypes", "{}"), new TypeToken<Map<Integer, Pair<String, Integer>>>(){}.getType());
|
||||
if (types != null) {
|
||||
for (Integer index : types.keySet()) {
|
||||
Pair<String, Integer> type = types.get(index);
|
||||
if (type != null && type.second != null) {
|
||||
int color = type.second;
|
||||
switch (color) {
|
||||
case 0xffdaa520:
|
||||
color = COLOR_DEFAULT;
|
||||
break;
|
||||
case 0xffff0000:
|
||||
color = COLOR_EXAM;
|
||||
break;
|
||||
case 0xffadff2f:
|
||||
color = COLOR_SHORT_QUIZ;
|
||||
break;
|
||||
case 0xff4050b5:
|
||||
color = COLOR_ESSAY;
|
||||
break;
|
||||
case 0xff673ab7:
|
||||
color = COLOR_PROJECT;
|
||||
break;
|
||||
case 0xffabcdef:
|
||||
color = COLOR_PT_MEETING;
|
||||
break;
|
||||
case 0xff4caf50:
|
||||
color = COLOR_EXCURSION;
|
||||
break;
|
||||
case 0xffffeb3b:
|
||||
color = COLOR_READING;
|
||||
break;
|
||||
}
|
||||
app.db.eventTypeDao().add(new EventType(profileId, index, type.first, color));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.events", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Event> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
int color = item.get("color").getAsInt();
|
||||
switch (color) {
|
||||
case 0xffdaa520:
|
||||
case 0xffff0000:
|
||||
case 0xffadff2f:
|
||||
case 0xff4050b5:
|
||||
case 0xff673ab7:
|
||||
case 0xffabcdef:
|
||||
case 0xff4caf50:
|
||||
case 0xffffeb3b:
|
||||
color = -1;
|
||||
break;
|
||||
}
|
||||
long id = item.get("id").getAsLong();
|
||||
Event itemObj = new Event(
|
||||
profileId,
|
||||
id,
|
||||
app.gson.fromJson(item.get("eventDate"), Date.class),
|
||||
app.gson.fromJson(item.get("startTime"), Time.class),
|
||||
item.get("topic").getAsString(),
|
||||
color,
|
||||
item.get("type").getAsInt(),
|
||||
(loginStore.type != LOGIN_TYPE_MOBIDZIENNIK || id >= 1420070400000L) && item.get("addedManually").getAsBoolean(),
|
||||
item.get("teacherId").getAsInt(),
|
||||
item.get("subjectId").getAsInt(),
|
||||
item.get("teamId").getAsInt());
|
||||
if (item.get("sharedBy") != null) {
|
||||
itemObj.sharedBy = item.get("sharedBy").getAsString();
|
||||
itemObj.sharedByName = item.get("sharedByName").getAsString();
|
||||
}
|
||||
Metadata metadataObj = new Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
itemObj.id,
|
||||
item.get("seen").getAsBoolean(),
|
||||
item.get("notified").getAsBoolean(),
|
||||
item.get("addedDate").getAsLong()
|
||||
);
|
||||
if (itemObj.id == -1)
|
||||
continue;
|
||||
itemList.add(itemObj);
|
||||
metadataList.add(metadataObj);
|
||||
}
|
||||
app.db.eventDao().addAll(itemList);
|
||||
}
|
||||
items = new JsonParser().parse(gp(p, "app.register.homeworksNew", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Event> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
Event itemObj = new Event(
|
||||
profileId,
|
||||
item.get("id").getAsLong(),
|
||||
app.gson.fromJson(item.get("eventDate"), Date.class),
|
||||
app.gson.fromJson(item.get("startTime"), Time.class),
|
||||
item.get("topic").getAsString(),
|
||||
-1,
|
||||
TYPE_HOMEWORK,
|
||||
item.get("addedManually").getAsBoolean(),
|
||||
item.get("teacherId").getAsInt(),
|
||||
item.get("subjectId").getAsInt(),
|
||||
item.get("teamId").getAsInt());
|
||||
if (item.get("sharedBy") != null) {
|
||||
itemObj.sharedBy = item.get("sharedBy").getAsString();
|
||||
itemObj.sharedByName = item.get("sharedByName").getAsString();
|
||||
}
|
||||
Metadata metadataObj = new Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
itemObj.id,
|
||||
item.get("seen").getAsBoolean(),
|
||||
item.get("notified").getAsBoolean(),
|
||||
item.get("addedDate").getAsLong()
|
||||
);
|
||||
if (itemObj.id == -1)
|
||||
continue;
|
||||
itemList.add(itemObj);
|
||||
metadataList.add(metadataObj);
|
||||
}
|
||||
app.db.eventDao().addAll(itemList);
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.gradeCategories", "[]")).getAsJsonArray();
|
||||
LongSparseArray<Pair<String, Integer>> gradeCategories = new LongSparseArray<>();
|
||||
if (items != null) {
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
if (item.get("id").getAsLong() == -1)
|
||||
continue;
|
||||
gradeCategories.put(item.get("id").getAsLong(),
|
||||
new Pair<>(item.get("description").getAsString(), item.get("color").getAsInt()));
|
||||
}
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.grades", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Grade> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
long categoryId = item.get("categoryId").getAsInt();
|
||||
Pair<String, Integer> category = gradeCategories.get(categoryId);
|
||||
Grade itemObj = new Grade(
|
||||
profileId,
|
||||
item.get("id").getAsLong(),
|
||||
category != null ? category.first : "",
|
||||
category != null && category.second != null ? category.second : 0xff0000ff,
|
||||
item.get("description").getAsString(),
|
||||
item.get("name").getAsString(),
|
||||
item.get("value").getAsFloat(),
|
||||
item.get("weight").getAsInt(),
|
||||
item.get("semester").getAsInt(),
|
||||
item.get("teacherId").getAsInt(),
|
||||
item.get("subjectId").getAsInt());
|
||||
itemObj.type = item.get("type").getAsInt();
|
||||
if (loginStore.type == LOGIN_TYPE_IUCZNIOWIE && itemObj.type != 0)
|
||||
continue;
|
||||
Metadata metadataObj = new Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
itemObj.id,
|
||||
item.get("seen").getAsBoolean(),
|
||||
item.get("notified").getAsBoolean(),
|
||||
item.get("addedDate").getAsLong()
|
||||
);
|
||||
if (itemObj.id == -1)
|
||||
continue;
|
||||
itemList.add(itemObj);
|
||||
metadataList.add(metadataObj);
|
||||
}
|
||||
app.db.gradeDao().addAll(itemList);
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.notices", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Notice> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
Notice itemObj = new Notice(
|
||||
profileId,
|
||||
item.get("id").getAsLong() + (loginStore.type == LOGIN_TYPE_IUCZNIOWIE ? 32768 : 0),
|
||||
item.get("reason").getAsString(),
|
||||
item.get("semester").getAsInt(),
|
||||
item.get("type").getAsInt(),
|
||||
item.get("teacherId").getAsInt());
|
||||
Metadata metadataObj = new Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_NOTICE,
|
||||
itemObj.id,
|
||||
item.get("seen").getAsBoolean(),
|
||||
item.get("notified").getAsBoolean(),
|
||||
item.get("addedDate").getAsLong()
|
||||
);
|
||||
if (itemObj.id == -1)
|
||||
continue;
|
||||
itemList.add(itemObj);
|
||||
metadataList.add(metadataObj);
|
||||
}
|
||||
app.db.noticeDao().addAll(itemList);
|
||||
}
|
||||
|
||||
items = new JsonParser().parse(gp(p, "app.register.attendances", "[]")).getAsJsonArray();
|
||||
if (items != null) {
|
||||
List<Attendance> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : items) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
Attendance itemObj = new Attendance(
|
||||
profileId,
|
||||
item.get("id").getAsLong(),
|
||||
item.get("teacherId").getAsInt(),
|
||||
item.get("subjectId").getAsInt(),
|
||||
item.get("semester").getAsInt(),
|
||||
item.get("lessonTopic").getAsString(),
|
||||
app.gson.fromJson(item.get("lessonDate"), Date.class),
|
||||
app.gson.fromJson(item.get("startTime"), Time.class),
|
||||
item.get("type").getAsInt());
|
||||
Metadata metadataObj = new Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
itemObj.id,
|
||||
item.get("seen").getAsBoolean(),
|
||||
item.get("notified").getAsBoolean(),
|
||||
item.get("addedDate").getAsLong()
|
||||
);
|
||||
if (itemObj.id == -1)
|
||||
continue;
|
||||
itemList.add(itemObj);
|
||||
metadataList.add(metadataObj);
|
||||
}
|
||||
app.db.attendanceDao().addAll(itemList);
|
||||
}
|
||||
|
||||
|
||||
tItem = new JsonParser().parse(gp(p, "app.register.timetable", "{weekdays: [], lessonChanges: [], lessonAdditions: []}")).getAsJsonObject();
|
||||
if (tItem != null) {
|
||||
|
||||
List<Lesson> itemLessonList = new ArrayList<>();
|
||||
for (JsonElement weekDayEl : tItem.getAsJsonArray("weekdays")) {
|
||||
JsonObject weekDay = weekDayEl.getAsJsonObject();
|
||||
int weekDayNum = weekDay.get("weekDay").getAsInt();
|
||||
for (JsonElement itemEl : weekDay.getAsJsonArray("lessons")) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
Lesson itemObj = new Lesson(
|
||||
profileId,
|
||||
weekDayNum,
|
||||
app.gson.fromJson(item.get("startTime"), Time.class),
|
||||
app.gson.fromJson(item.get("endTime"), Time.class)
|
||||
);
|
||||
itemObj.classroomName = item.get("classroomName").getAsString();
|
||||
itemObj.subjectId = item.get("subjectId").getAsInt();
|
||||
itemObj.teacherId = item.get("teacherId").getAsInt();
|
||||
itemObj.teamId = item.get("teamId").getAsInt();
|
||||
itemLessonList.add(itemObj);
|
||||
}
|
||||
}
|
||||
app.db.lessonDao().addAll(itemLessonList);
|
||||
|
||||
List<LessonChange> itemList = new ArrayList<>();
|
||||
for (JsonElement itemEl : tItem.getAsJsonArray("lessonChanges")) {
|
||||
JsonObject item = itemEl.getAsJsonObject();
|
||||
LessonChange itemObj = new LessonChange(
|
||||
profileId,
|
||||
app.gson.fromJson(item.get("lessonDate"), Date.class),
|
||||
app.gson.fromJson(item.get("startTime"), Time.class),
|
||||
app.gson.fromJson(item.get("endTime"), Time.class));
|
||||
itemObj.classroomName = item.get("classroomName").getAsString();
|
||||
itemObj.subjectId = item.get("subjectId").getAsInt();
|
||||
itemObj.teacherId = item.get("teacherId").getAsInt();
|
||||
itemObj.teamId = item.get("teamId").getAsInt();
|
||||
itemObj.type = item.get("type").getAsInt();
|
||||
Metadata metadataObj = new Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
itemObj.id,
|
||||
item.get("seen").getAsBoolean(),
|
||||
item.get("notified").getAsBoolean(),
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
if (itemObj.id == -1)
|
||||
continue;
|
||||
itemList.add(itemObj);
|
||||
metadataList.add(metadataObj);
|
||||
}
|
||||
app.db.lessonChangeDao().addAll(itemList);
|
||||
}
|
||||
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_HOMEWORK, getString(R.string.event_type_homework), COLOR_HOMEWORK));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_DEFAULT, getString(R.string.event_other), COLOR_DEFAULT));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_EXAM, getString(R.string.event_exam), COLOR_EXAM));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_SHORT_QUIZ, getString(R.string.event_short_quiz), COLOR_SHORT_QUIZ));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_ESSAY, getString(R.string.event_essay), COLOR_SHORT_QUIZ));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_PROJECT, getString(R.string.event_project), COLOR_PROJECT));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_PT_MEETING, getString(R.string.event_pt_meeting), COLOR_PT_MEETING));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_EXCURSION, getString(R.string.event_excursion), COLOR_EXCURSION));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_READING, getString(R.string.event_reading), COLOR_READING));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_CLASS_EVENT, getString(R.string.event_class_event), COLOR_CLASS_EVENT));
|
||||
app.db.eventTypeDao().add(new EventType(profileId, TYPE_INFORMATION, getString(R.string.event_information), COLOR_INFORMATION));
|
||||
|
||||
if (profile.getLuckyNumberDate() != null) {
|
||||
app.db.luckyNumberDao().add(new LuckyNumber(profile.getId(), profile.getLuckyNumberDate(), profile.getLuckyNumber()));
|
||||
}
|
||||
app.db.profileDao().add(profile);
|
||||
app.db.loginStoreDao().add(loginStore);
|
||||
app.db.metadataDao().addAllIgnore(metadataList);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
app.appConfig.appInstalledTime = app.getPackageManager().getPackageInfo(app.getPackageName(), 0).firstInstallTime;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
app.appConfig.appRateSnackbarTime = app.appConfig.appInstalledTime + 2 * 24 * 60 * 60 * 1000;
|
||||
app.appConfig.loginFinished = true;
|
||||
app.saveConfig("loginFinished", "appInstalledTime", "appRateSnackbarTime");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,132 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMigrationSyncBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncService;
|
||||
|
||||
public class LoginMigrationSyncFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginMigrationSyncBinding b;
|
||||
private static final String TAG = "LoginMigrationSync";
|
||||
private List<String> profileNameList = new ArrayList<>();
|
||||
private int profileIndex = 0;
|
||||
|
||||
public LoginMigrationSyncFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_migration_sync, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
private void begin() {
|
||||
AsyncTask.execute(() -> {
|
||||
if (getActivity() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Profile profileObject: app.db.profileDao().getAllNow()) {
|
||||
profileNameList.add(profileObject.getName());
|
||||
}
|
||||
|
||||
getActivity().runOnUiThread(() -> {
|
||||
profileIndex = 0;
|
||||
b.loginSyncSubtitle1.setText(Html.fromHtml(getString(R.string.login_sync_subtitle_1_format, profileNameList.size() > profileIndex ? profileNameList.get(profileIndex) : " ")));
|
||||
});
|
||||
SyncJob.run(app, -1, -1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
SyncService.customCallback = new SyncCallback() {
|
||||
@Override public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) { }
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profileFull) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
if (profileFull != null) {
|
||||
// a profile is finished
|
||||
profileIndex++;
|
||||
b.loginSyncSubtitle1.setText(Html.fromHtml(getString(R.string.login_sync_subtitle_1_format, profileIndex < profileNameList.size() ? profileNameList.get(profileIndex) : profileNameList.get(profileNameList.size()-1))));
|
||||
}
|
||||
else {
|
||||
// all profiles are finished
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
b.loginSyncProgressBar.setMax(SyncService.maxProgress);
|
||||
b.loginSyncProgressBar.setProgress(SyncService.progress);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
b.loginSyncSubtitle2.setText(getString(R.string.login_sync_subtitle_2_format, getString(stringResId)));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
begin();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,148 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikBinding;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_ARCHIVED;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_LOGIN;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_SERVER_ADDRESS;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_OLD_PASSWORD;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
|
||||
public class LoginMobidziennikFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginMobidziennikBinding b;
|
||||
private static final String TAG = "LoginMobidziennik";
|
||||
|
||||
public LoginMobidziennikFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_mobidziennik, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
case CODE_INVALID_LOGIN:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
case CODE_OLD_PASSWORD:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_old_password));
|
||||
break;
|
||||
case CODE_ARCHIVED:
|
||||
b.loginUsernameLayout.setError(getString(R.string.sync_error_archived));
|
||||
break;
|
||||
case CODE_INVALID_SERVER_ADDRESS:
|
||||
b.loginServerAddressLayout.setError(getString(R.string.login_error_incorrect_address));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
b.helpButton.setOnClickListener((v) -> nav.navigate(R.id.loginMobidziennikHelpFragment, null, LoginActivity.navOptions));
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
|
||||
b.loginButton.setOnClickListener((v) -> {
|
||||
boolean errors = false;
|
||||
|
||||
b.loginServerAddressLayout.setError(null);
|
||||
b.loginUsernameLayout.setError(null);
|
||||
b.loginPasswordLayout.setError(null);
|
||||
|
||||
Editable serverNameEditable = b.loginServerAddress.getText();
|
||||
Editable usernameEditable = b.loginUsername.getText();
|
||||
Editable passwordEditable = b.loginPassword.getText();
|
||||
if (serverNameEditable == null || serverNameEditable.length() == 0) {
|
||||
b.loginServerAddressLayout.setError(getString(R.string.login_error_no_address));
|
||||
errors = true;
|
||||
}
|
||||
if (usernameEditable == null || usernameEditable.length() == 0) {
|
||||
b.loginUsernameLayout.setError(getString(R.string.login_error_no_login));
|
||||
errors = true;
|
||||
}
|
||||
if (passwordEditable == null || passwordEditable.length() == 0) {
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_no_password));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
String serverName = serverNameEditable.toString().toLowerCase().replaceAll("(?:http://|www.|mobidziennik\\.pl|wizja\\.net|\\.)", "");
|
||||
String username = usernameEditable.toString().toLowerCase();
|
||||
String password = passwordEditable.toString();
|
||||
b.loginServerAddress.setText(serverName);
|
||||
b.loginUsername.setText(username);
|
||||
if (!serverName.matches("^[a-z0-9_\\-]+$")) {
|
||||
b.loginServerAddressLayout.setError(getString(R.string.login_error_incorrect_address));
|
||||
errors = true;
|
||||
}
|
||||
if (!username.matches("^[a-z0-9_\\-@+.]+$")) {
|
||||
b.loginUsernameLayout.setError(getString(R.string.login_error_incorrect_login));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("loginType", LOGIN_TYPE_MOBIDZIENNIK);
|
||||
args.putString("serverName", serverName);
|
||||
args.putString("username", username);
|
||||
args.putString("password", password);
|
||||
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikHelpBinding;
|
||||
|
||||
public class LoginMobidziennikHelpFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginMobidziennikHelpBinding b;
|
||||
private static final String TAG = "LoginMobidziennikHelp";
|
||||
|
||||
public LoginMobidziennikHelpFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_mobidziennik_help, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
|
||||
public class LoginProfileObject {
|
||||
LoginStore loginStore = null;
|
||||
List<Profile> profileList = new ArrayList<>();
|
||||
List<Boolean> selectedList = new ArrayList<>();
|
||||
|
||||
public LoginProfileObject(@NonNull LoginStore loginStore, @NonNull List<Profile> profileList) {
|
||||
this.loginStore = loginStore;
|
||||
this.profileList = profileList;
|
||||
for (Profile ignored : profileList) {
|
||||
selectedList.add(true);
|
||||
}
|
||||
}
|
||||
|
||||
public LoginProfileObject addProfile(Profile profile) {
|
||||
profileList.add(profile);
|
||||
selectedList.add(true);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginProgressBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_OTHER;
|
||||
|
||||
public class LoginProgressFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginProgressBinding b;
|
||||
private static final String TAG = "LoginProgress";
|
||||
|
||||
public LoginProgressFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_progress, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
Bundle args = getArguments();
|
||||
|
||||
LoginActivity.error = null;
|
||||
|
||||
if (args == null) {
|
||||
LoginActivity.error = new AppError(TAG, 72, CODE_OTHER, getString(R.string.login_error_no_arguments));
|
||||
nav.navigateUp();
|
||||
return;
|
||||
}
|
||||
|
||||
int loginType = args.getInt("loginType", -1);
|
||||
|
||||
LoginStore loginStore = new LoginStore(-1, loginType, new JsonObject());
|
||||
loginStore.copyFrom(args);
|
||||
|
||||
Edziennik.getApi(app, loginType).sync(getActivity(), new SyncCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
// because these callbacks are always on a worker thread
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
LoginActivity.profileObjects.add(new LoginProfileObject(
|
||||
loginStore,
|
||||
profileList));
|
||||
nav.navigate(R.id.loginSummaryFragment, null, LoginActivity.navOptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profileFull) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
LoginActivity.error = error;
|
||||
// because these callbacks are always on a worker thread
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
nav.navigateUp();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
|
||||
}
|
||||
}, -1, null, loginStore);
|
||||
|
||||
/*if (true)
|
||||
return;
|
||||
JsonObject loginData = new JsonObject();
|
||||
loginData.addProperty("serverName", b.loginServerAddress.getText().toString());
|
||||
loginData.addProperty("username", b.loginUsername.getText().toString());
|
||||
loginData.addProperty("password", b.loginPassword.getText().toString());
|
||||
getApi(app, LOGIN_TYPE_MOBIDZIENNIK).sync(getActivity(), new Edziennik.DataCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
int profileId = app.profileLastId()+1;
|
||||
if (profileList.size() == 1) {
|
||||
Profile profile = profileList.get(0);
|
||||
saveProfile(profile, loginStore, profileId, profileId);
|
||||
finishSaving();
|
||||
return;
|
||||
}
|
||||
List<String> profileNames = new ArrayList<>();
|
||||
for (Profile profile: profileList) {
|
||||
profileNames.add(profile.name);
|
||||
}
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.sync_multiaccount_select_students)
|
||||
.items(profileNames)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.neutralText(R.string.help)
|
||||
.autoDismiss(false)
|
||||
.canceledOnTouchOutside(false)
|
||||
.onNeutral((dialog, which) ->
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.help)
|
||||
.content(R.string.sync_multiaccount_select_students_text)
|
||||
.positiveText(R.string.ok)
|
||||
.show()
|
||||
)
|
||||
.onNegative(((dialog, which) -> dialog.dismiss()))
|
||||
.itemsCallbackMultiChoice(null, (dialog, which, text) -> {
|
||||
// create new profiles, then restart the application or sth
|
||||
if (text.length < 1 || which.length < 1) {
|
||||
Toast.makeText(app, R.string.sync_multiaccount_select_students_error, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
dialog.dismiss();
|
||||
int pos = 0;
|
||||
for (int index: which) {
|
||||
Profile profile = profileList.get(index);
|
||||
saveProfile(profile, loginStore, profileId+(pos++), profileId);
|
||||
}
|
||||
finishSaving();
|
||||
|
||||
|
||||
String list = "";
|
||||
for (ProfileFull profileFull: app.db.profileDao().getAllFullNow()) {
|
||||
d(TAG, profileFull.toString());
|
||||
list += profileFull.studentNameLong+" student ID "+profileFull.getStudentData("studentId", -1)+"\n";
|
||||
}
|
||||
d(TAG, loginStore.toString());
|
||||
list += loginStore.getLoginData("username", "(NO USERNAME)")+"\n";
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title("Znaleziono profile")
|
||||
.content(list)
|
||||
.positiveText("OK")
|
||||
.show();
|
||||
|
||||
|
||||
return false;
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profile) {
|
||||
Toast.makeText(activityContext, "Zakończono", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, int errorCode, String errorText, Throwable throwable, String apiResponse) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
|
||||
}
|
||||
}, -1, null, new LoginStore(-1, LOGIN_TYPE_MOBIDZIENNIK, loginData));*/
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSummaryBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.RowLoginProfileListItemBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
|
||||
public class LoginSummaryFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginSummaryBinding b;
|
||||
private static final String TAG = "LoginSummary";
|
||||
|
||||
public LoginSummaryFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_summary, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
LoginActivity.firstCompleted = true;
|
||||
|
||||
List<ItemProfileModel> profileList = new ArrayList<>();
|
||||
int index = 0;
|
||||
for (LoginProfileObject profileObject: LoginActivity.profileObjects) {
|
||||
int subIndex = 0;
|
||||
for (Profile profile: profileObject.profileList) {
|
||||
ItemProfileModel profileModel = new ItemProfileModel(
|
||||
index,
|
||||
subIndex,
|
||||
profile.getName(),
|
||||
profileObject.loginStore.type,
|
||||
profileObject.selectedList.get(subIndex)
|
||||
);
|
||||
profileList.add(profileModel);
|
||||
subIndex++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
b.profileListView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
b.profileListView.setAdapter(new ProfileListAdapter(profileList));
|
||||
|
||||
b.registerMeSwitch.setOnCheckedChangeListener(((buttonView, isChecked) -> {
|
||||
if (!isChecked) {
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.login_summary_unregister_title)
|
||||
.content(R.string.login_summary_unregister_text)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.cancel)
|
||||
.onNegative(((dialog, which) -> {
|
||||
b.registerMeSwitch.setChecked(true);
|
||||
}))
|
||||
.show();
|
||||
}
|
||||
}));
|
||||
|
||||
b.anotherButton.setOnClickListener((v -> nav.navigate(R.id.loginChooserFragment, null, LoginActivity.navOptions)));
|
||||
|
||||
b.finishButton.setOnClickListener(v -> {
|
||||
if (LoginActivity.privacyPolicyAccepted) {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("registrationAllowed", b.registerMeSwitch.isChecked());
|
||||
nav.navigate(R.id.loginSyncFragment, args, LoginActivity.navOptions);
|
||||
return;
|
||||
}
|
||||
boolean profileSelected = true;
|
||||
for (LoginProfileObject profileObject: LoginActivity.profileObjects) {
|
||||
if (profileObject.selectedList.size() == 0 && profileSelected)
|
||||
profileSelected = false;
|
||||
}
|
||||
if (!profileSelected) {
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.login_summary_no_profiles_title)
|
||||
.content(R.string.login_summary_no_profiles_text)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.privacy_policy)
|
||||
.content(Html.fromHtml("Korzystając z aplikacji potwierdzasz <a href=\"http://szkolny.eu/privacy-policy\">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia."))
|
||||
.positiveText(R.string.i_agree)
|
||||
.neutralText(R.string.i_disagree)
|
||||
.onPositive(((dialog, which) -> {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("registrationAllowed", b.registerMeSwitch.isChecked());
|
||||
nav.navigate(R.id.loginSyncFragment, args, LoginActivity.navOptions);
|
||||
}))
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
class ItemProfileModel {
|
||||
int listIndex;
|
||||
int listSubIndex;
|
||||
String name;
|
||||
int loginType;
|
||||
boolean selected;
|
||||
|
||||
public ItemProfileModel(int listIndex, int listSubIndex, String name, int loginType, boolean selected) {
|
||||
this.listIndex = listIndex;
|
||||
this.listSubIndex = listSubIndex;
|
||||
this.name = name;
|
||||
this.loginType = loginType;
|
||||
this.selected = selected;
|
||||
}
|
||||
}
|
||||
|
||||
public class ProfileListAdapter extends RecyclerView.Adapter<ProfileListAdapter.ViewHolder> {
|
||||
private List<ItemProfileModel> profileList;
|
||||
|
||||
public ProfileListAdapter(List<ItemProfileModel> profileList) {
|
||||
this.profileList = profileList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
RowLoginProfileListItemBinding b = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.row_login_profile_list_item, parent, false);
|
||||
return new ViewHolder(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
RowLoginProfileListItemBinding b = holder.b;
|
||||
ItemProfileModel m = profileList.get(position);
|
||||
|
||||
b.textView.setText(m.name);
|
||||
b.checkBox.setChecked(m.selected);
|
||||
b.checkBox.jumpDrawablesToCurrentState();
|
||||
View.OnClickListener onClickListener = v -> {
|
||||
if (v instanceof CheckBox) {
|
||||
m.selected = ((CheckBox) v).isChecked();
|
||||
} else {
|
||||
m.selected = !m.selected;
|
||||
b.checkBox.setChecked(m.selected);
|
||||
b.checkBox.jumpDrawablesToCurrentState();
|
||||
}
|
||||
LoginActivity.profileObjects.get(m.listIndex).selectedList.set(m.listSubIndex, m.selected);
|
||||
};
|
||||
b.checkBox.setOnClickListener(onClickListener);
|
||||
b.getRoot().setOnClickListener(onClickListener);
|
||||
//b.root.setOnClickListener(onClickListener);
|
||||
//holder.bind(b.textView, onClickListener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return profileList.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
RowLoginProfileListItemBinding b;
|
||||
|
||||
public ViewHolder(@NonNull RowLoginProfileListItemBinding b) {
|
||||
super(b.getRoot());
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSyncErrorBinding;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class LoginSyncErrorFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginSyncErrorBinding b;
|
||||
private static final String TAG = "LoginSyncError";
|
||||
|
||||
public LoginSyncErrorFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_sync_error, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.errorDetails.setText(LoginActivity.error == null ? "" : LoginActivity.error.asReadableString(getActivity()));
|
||||
|
||||
b.reportButton.setOnClickListener((v -> {
|
||||
app.apiEdziennik.guiReportError(getActivity(), LoginActivity.error, null);
|
||||
}));
|
||||
|
||||
b.nextButton.setOnClickListener((v -> {
|
||||
nav.navigate(R.id.loginFinishFragment, null, LoginActivity.navOptions);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,227 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSyncBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventType;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncService;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_CLASS_EVENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_DEFAULT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_EXAM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_EXCURSION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_INFORMATION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_PROJECT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_PT_MEETING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_READING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.COLOR_SHORT_QUIZ;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_CLASS_EVENT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_DEFAULT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_ESSAY;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_EXAM;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_EXCURSION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_INFORMATION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_PROJECT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_PT_MEETING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_READING;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_SHORT_QUIZ;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_DISABLED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_ENABLED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_UNSPECIFIED;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class LoginSyncFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginSyncBinding b;
|
||||
private static final String TAG = "LoginSyncFragment";
|
||||
private List<String> profileNameList = new ArrayList<>();
|
||||
private int profileIndex = 0;
|
||||
|
||||
public LoginSyncFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_sync, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
private void begin() {
|
||||
AsyncTask.execute(() -> {
|
||||
if (getActivity() == null) {
|
||||
return;
|
||||
}
|
||||
int profileId = app.profileLastId()+1;
|
||||
final int firstProfileId = profileId;
|
||||
int loginStoreId = profileId;
|
||||
// profileId contains the first ID free to use
|
||||
|
||||
for (LoginProfileObject profileObject: LoginActivity.profileObjects) {
|
||||
int subIndex = 0;
|
||||
for (Profile profile: profileObject.profileList) {
|
||||
if (profileObject.selectedList.get(subIndex)) {
|
||||
saveProfile(
|
||||
profile,
|
||||
profileObject.loginStore,
|
||||
profileId,
|
||||
loginStoreId
|
||||
);
|
||||
profileNameList.add(profile.getName());
|
||||
profileId++;
|
||||
}
|
||||
subIndex++;
|
||||
}
|
||||
loginStoreId = profileId;
|
||||
}
|
||||
|
||||
for (Profile profile: app.db.profileDao().getAllNow()) {
|
||||
d(TAG, profile.toString());
|
||||
}
|
||||
for (LoginStore loginStore: app.db.loginStoreDao().getAllNow()) {
|
||||
d(TAG, loginStore.toString());
|
||||
}
|
||||
|
||||
if (app.appConfig.loginFinished) {
|
||||
LoginFinishFragment.firstRun = false;
|
||||
}
|
||||
else {
|
||||
LoginFinishFragment.firstRun = true;
|
||||
app.appConfig.loginFinished = true;
|
||||
app.saveConfig("loginFinished");
|
||||
}
|
||||
LoginFinishFragment.firstProfileId = firstProfileId;
|
||||
|
||||
getActivity().runOnUiThread(() -> {
|
||||
profileIndex = 0;
|
||||
b.loginSyncSubtitle1.setText(Html.fromHtml(getString(R.string.login_sync_subtitle_1_format, profileNameList.size() > profileIndex ? profileNameList.get(profileIndex) : " ")));
|
||||
});
|
||||
SyncJob.run(app, firstProfileId, -1);
|
||||
});
|
||||
}
|
||||
|
||||
private void saveProfile(Profile profile, LoginStore loginStore, int profileId, int loginStoreId) {
|
||||
profile.setRegistration(REGISTRATION_UNSPECIFIED);
|
||||
if (getArguments() != null) {
|
||||
if (getArguments().getBoolean("registrationAllowed", false)) {
|
||||
profile.setRegistration(REGISTRATION_ENABLED);
|
||||
}
|
||||
else {
|
||||
profile.setRegistration(REGISTRATION_DISABLED);
|
||||
}
|
||||
}
|
||||
profile.setId(profileId);
|
||||
profile.setLoginStoreId(loginStoreId);
|
||||
loginStore.id = loginStoreId;
|
||||
List<EventType> typeList = new ArrayList<>();
|
||||
typeList.add(new EventType(profileId, TYPE_HOMEWORK, getString(R.string.event_type_homework), COLOR_HOMEWORK));
|
||||
typeList.add(new EventType(profileId, TYPE_DEFAULT, getString(R.string.event_other), COLOR_DEFAULT));
|
||||
typeList.add(new EventType(profileId, TYPE_EXAM, getString(R.string.event_exam), COLOR_EXAM));
|
||||
typeList.add(new EventType(profileId, TYPE_SHORT_QUIZ, getString(R.string.event_short_quiz), COLOR_SHORT_QUIZ));
|
||||
typeList.add(new EventType(profileId, TYPE_ESSAY, getString(R.string.event_essay), COLOR_SHORT_QUIZ));
|
||||
typeList.add(new EventType(profileId, TYPE_PROJECT, getString(R.string.event_project), COLOR_PROJECT));
|
||||
typeList.add(new EventType(profileId, TYPE_PT_MEETING, getString(R.string.event_pt_meeting), COLOR_PT_MEETING));
|
||||
typeList.add(new EventType(profileId, TYPE_EXCURSION, getString(R.string.event_excursion), COLOR_EXCURSION));
|
||||
typeList.add(new EventType(profileId, TYPE_READING, getString(R.string.event_reading), COLOR_READING));
|
||||
typeList.add(new EventType(profileId, TYPE_CLASS_EVENT, getString(R.string.event_class_event), COLOR_CLASS_EVENT));
|
||||
typeList.add(new EventType(profileId, TYPE_INFORMATION, getString(R.string.event_information), COLOR_INFORMATION));
|
||||
app.db.eventTypeDao().addAll(typeList);
|
||||
app.profileSaveFull(profile, loginStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
LoginActivity.error = null;
|
||||
|
||||
SyncService.customCallback = new SyncCallback() {
|
||||
@Override public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) { }
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profileFull) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
if (profileFull != null) {
|
||||
// a profile is finished
|
||||
profileIndex++;
|
||||
b.loginSyncSubtitle1.setText(Html.fromHtml(getString(R.string.login_sync_subtitle_1_format, profileIndex < profileNameList.size() ? profileNameList.get(profileIndex) : profileNameList.get(profileNameList.size()-1))));
|
||||
}
|
||||
else {
|
||||
// all profiles are finished
|
||||
nav.navigate(R.id.loginFinishFragment, null , LoginActivity.navOptions);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
LoginActivity.error = error;
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
nav.navigate(R.id.loginSyncErrorFragment, null, LoginActivity.navOptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
b.loginSyncProgressBar.setMax(SyncService.maxProgress);
|
||||
b.loginSyncProgressBar.setProgress(SyncService.progress);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
getActivity().runOnUiThread(() -> {
|
||||
b.loginSyncSubtitle2.setText(getString(R.string.login_sync_subtitle_2_format, getString(stringResId)));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
begin();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginTemplateBinding;
|
||||
|
||||
public class LoginTemplateFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginTemplateBinding b;
|
||||
private static final String TAG = "LoginTemplate";
|
||||
|
||||
public LoginTemplateFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_template, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
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 androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.QrScannerActivity;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_EXPIRED_TOKEN;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_PIN;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_SYMBOL;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_INVALID_TOKEN;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_VULCAN;
|
||||
|
||||
public class LoginVulcanFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginVulcanBinding b;
|
||||
private static final String TAG = "LoginVulcan";
|
||||
|
||||
public LoginVulcanFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_vulcan, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
case CODE_INVALID_TOKEN:
|
||||
b.loginTokenLayout.setError(getString(R.string.login_error_incorrect_token));
|
||||
break;
|
||||
case CODE_EXPIRED_TOKEN:
|
||||
b.loginTokenLayout.setError(getString(R.string.login_error_expired_token));
|
||||
break;
|
||||
case CODE_INVALID_SYMBOL:
|
||||
b.loginSymbolLayout.setError(getString(R.string.login_error_incorrect_symbol));
|
||||
break;
|
||||
case CODE_INVALID_PIN:
|
||||
if (!"?".equals(error.errorText)) {
|
||||
b.loginPinLayout.setError(getString(R.string.login_error_incorrect_pin_format, error.errorText));
|
||||
break;
|
||||
}
|
||||
b.loginPinLayout.setError(getString(R.string.login_error_incorrect_pin));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
b.helpButton.setOnClickListener((v) -> nav.navigate(R.id.loginVulcanHelpFragment, null, LoginActivity.navOptions));
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
|
||||
b.loginQrScan.setImageDrawable(new IconicsDrawable(getActivity()).icon(CommunityMaterial.Icon2.cmd_qrcode).color(IconicsColor.colorInt(Color.BLACK)).size(IconicsSize.dp(72)));
|
||||
b.loginQrScan.setOnClickListener((v -> {
|
||||
QrScannerActivity.resultHandler = result -> {
|
||||
try {
|
||||
String qr = result.getText();
|
||||
String data = Utils.VulcanQrEncryptionUtils.decode(qr);
|
||||
Matcher matcher = Pattern.compile("CERT#https?://.+?/([A-z]+)/mobile-api#([A-z0-9]+)#ENDCERT").matcher(data);
|
||||
if (matcher.find()) {
|
||||
b.loginToken.setText(matcher.group(2));
|
||||
b.loginSymbol.setText(matcher.group(1));
|
||||
if(b.loginPin.requestFocus()) {
|
||||
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ShortBufferException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
startActivity(new Intent(getContext(), QrScannerActivity.class));
|
||||
}));
|
||||
|
||||
b.loginButton.setOnClickListener((v) -> {
|
||||
boolean errors = false;
|
||||
|
||||
b.loginTokenLayout.setError(null);
|
||||
b.loginSymbolLayout.setError(null);
|
||||
b.loginPinLayout.setError(null);
|
||||
|
||||
Editable tokenEditable = b.loginToken.getText();
|
||||
Editable symbolEditable = b.loginSymbol.getText();
|
||||
Editable pinEditable = b.loginPin.getText();
|
||||
if (tokenEditable == null || tokenEditable.length() == 0) {
|
||||
b.loginTokenLayout.setError(getString(R.string.login_error_no_token));
|
||||
errors = true;
|
||||
}
|
||||
if (symbolEditable == null || symbolEditable.length() == 0) {
|
||||
b.loginSymbolLayout.setError(getString(R.string.login_error_no_symbol));
|
||||
errors = true;
|
||||
}
|
||||
if (pinEditable == null || pinEditable.length() == 0) {
|
||||
b.loginPinLayout.setError(getString(R.string.login_error_no_pin));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
String token = tokenEditable.toString().toUpperCase();
|
||||
String symbol = symbolEditable.toString().toLowerCase();
|
||||
String pin = pinEditable.toString();
|
||||
b.loginToken.setText(token);
|
||||
b.loginSymbol.setText(symbol);
|
||||
b.loginPin.setText(pin);
|
||||
if (!token.matches("[A-Z0-9]{5,12}")) {
|
||||
b.loginTokenLayout.setError(getString(R.string.login_error_incorrect_token));
|
||||
errors = true;
|
||||
}
|
||||
if (!symbol.matches("[a-z0-9]+")) {
|
||||
b.loginSymbolLayout.setError(getString(R.string.login_error_incorrect_symbol));
|
||||
errors = true;
|
||||
}
|
||||
if (!pin.matches("[a-z0-9_]+")) {
|
||||
b.loginPinLayout.setError(getString(R.string.login_error_incorrect_pin));
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
errors = false;
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("loginType", LOGIN_TYPE_VULCAN);
|
||||
args.putString("deviceToken", token);
|
||||
args.putString("deviceSymbol", symbol);
|
||||
args.putString("devicePin", pin);
|
||||
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions);
|
||||
});
|
||||
}// narysowac raz dwa trzy cztery wyresy funkcji ktore sa tak dzielone
|
||||
// nire wnikac w szkczegoly jak dzialaja
|
||||
// takie same sa funckje sinus comisinus
|
||||
//
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanHelpBinding;
|
||||
|
||||
public class LoginVulcanHelpFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
private NavController nav;
|
||||
private FragmentLoginVulcanHelpBinding b;
|
||||
private static final String TAG = "LoginVulcanHelp";
|
||||
|
||||
public LoginVulcanHelpFragment() { }
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_vulcan_help, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesItemBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Message.TYPE_DRAFT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Message.TYPE_SENT;
|
||||
|
||||
public class MessagesAdapter extends RecyclerView.Adapter<MessagesAdapter.ViewHolder> {
|
||||
private App app;
|
||||
public List<MessageFull> messageList = new ArrayList<>();
|
||||
private AdapterView.OnItemClickListener onItemClickListener;
|
||||
|
||||
|
||||
|
||||
public MessagesAdapter(App app, AdapterView.OnItemClickListener onItemClickListener) {
|
||||
this.app = app;
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
void setData(List<MessageFull> messageList) {
|
||||
this.messageList = messageList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
return new ViewHolder(DataBindingUtil.inflate(inflater, R.layout.messages_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
MessagesItemBinding b = holder.b;
|
||||
MessageFull message = messageList.get(position);
|
||||
|
||||
b.getRoot().setOnClickListener((v -> {
|
||||
onItemClickListener.onItemClick(null, v, position, position);
|
||||
}));
|
||||
|
||||
|
||||
ViewCompat.setTransitionName(b.getRoot(), String.valueOf(message.id));
|
||||
/*if (message.type == TYPE_RECEIVED) {
|
||||
b.messageSender.setText(message.senderFullName);
|
||||
}
|
||||
else if (message.type == TYPE_SENT && message.recipients != null && message.recipients.size() > 0) {
|
||||
StringBuilder senderText = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (MessageRecipientFull recipient: message.recipients) {
|
||||
if (!first) {
|
||||
senderText.append(", ");
|
||||
}
|
||||
first = false;
|
||||
senderText.append(recipient.fullName);
|
||||
}
|
||||
b.messageSender.setText(senderText.toString());
|
||||
}*/
|
||||
b.messageSubject.setText(message.subject);
|
||||
b.messageDate.setText(Date.fromMillis(message.addedDate).getFormattedStringShort());
|
||||
b.messageAttachmentImage.setVisibility(message.hasAttachments() ? View.VISIBLE : View.GONE);
|
||||
try {
|
||||
b.messageBody.setText(
|
||||
Html.fromHtml(
|
||||
message.body == null ? "" : message
|
||||
.body
|
||||
.substring(0, Math.min(message.body.length(), 200))
|
||||
.replaceAll("\\[META:[A-z0-9]+;[0-9-]+]", "")
|
||||
)
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO ???
|
||||
}
|
||||
|
||||
if (message.type == TYPE_SENT || message.type == TYPE_DRAFT || message.seen) {
|
||||
b.messageSender.setTextAppearance(b.messageSender.getContext(), R.style.NavView_TextView_Small);
|
||||
b.messageSender.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
|
||||
b.messageSubject.setTextAppearance(b.messageSubject.getContext(), R.style.NavView_TextView_Small);
|
||||
b.messageSubject.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
|
||||
b.messageDate.setTextAppearance(b.messageDate.getContext(), R.style.NavView_TextView_Small);
|
||||
b.messageDate.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
|
||||
}
|
||||
else {
|
||||
b.messageSender.setTextAppearance(b.messageSender.getContext(), R.style.NavView_TextView);
|
||||
b.messageSender.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
b.messageSubject.setTextAppearance(b.messageSubject.getContext(), R.style.NavView_TextView);
|
||||
b.messageSubject.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
b.messageDate.setTextAppearance(b.messageDate.getContext(), R.style.NavView_TextView);
|
||||
b.messageDate.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
}
|
||||
|
||||
/*if (message.type == TYPE_RECEIVED) {
|
||||
if (app.appConfig.teacherImages != null && app.appConfig.teacherImages.size() > 0 && app.appConfig.teacherImages.containsKey(message.senderId)) {
|
||||
Bitmap profileImage;
|
||||
profileImage = BitmapFactory.decodeFile(app.getFilesDir().getAbsolutePath()+"/teacher_"+message.senderId+".jpg");
|
||||
profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight()));
|
||||
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(app.getResources(), profileImage);
|
||||
roundDrawable.setCircular(true);
|
||||
b.messageProfileImage.setImageDrawable(roundDrawable);
|
||||
}
|
||||
else {
|
||||
b.messageProfileImage.setImageDrawable(null);
|
||||
int color = Colors.stringToMaterialColor(message.senderFullName);
|
||||
b.messageProfileBackground.getDrawable().setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
|
||||
b.messageProfileName.setTextColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
if (message.senderFullName == null) {
|
||||
b.messageProfileName.setText("N");
|
||||
} else {
|
||||
String[] nameParts = message.senderFullName.split(" ");
|
||||
b.messageProfileName.setText(nameParts[0].toUpperCase().charAt(0) + "" + nameParts[1].toUpperCase().charAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (message.type == TYPE_SENT && message.recipients != null && message.recipients.size() > 0) {
|
||||
MessageRecipientFull recipient = message.recipients.get(0);
|
||||
if (message.recipients.size() == 1 && app.appConfig.teacherImages != null && app.appConfig.teacherImages.size() > 0 && app.appConfig.teacherImages.containsKey(recipient.id)) {
|
||||
Bitmap profileImage;
|
||||
profileImage = BitmapFactory.decodeFile(app.getFilesDir().getAbsolutePath()+"/teacher_"+recipient.id+".jpg");
|
||||
profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight()));
|
||||
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(app.getResources(), profileImage);
|
||||
roundDrawable.setCircular(true);
|
||||
b.messageProfileImage.setImageDrawable(roundDrawable);
|
||||
}
|
||||
else {
|
||||
b.messageProfileImage.setImageDrawable(null);
|
||||
int color = Colors.stringToMaterialColor(recipient.fullName);
|
||||
b.messageProfileBackground.getDrawable().setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
|
||||
b.messageProfileName.setTextColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
if (recipient.fullName == null) {
|
||||
b.messageProfileName.setText("N");
|
||||
} else {
|
||||
String[] nameParts = recipient.fullName.split(" ");
|
||||
b.messageProfileName.setText(nameParts[0].toUpperCase().charAt(0) + "" + nameParts[1].toUpperCase().charAt(0));
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
MessagesUtils.MessageInfo messageInfo = MessagesUtils.getMessageInfo(app, message, 48, 24, 18, 12);
|
||||
b.messageProfileBackground.setImageBitmap(messageInfo.profileImage);
|
||||
b.messageSender.setText(messageInfo.profileName);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return messageList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
MessagesItemBinding b;
|
||||
|
||||
public ViewHolder(MessagesItemBinding b) {
|
||||
super(b.getRoot());
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.hootsuite.nachos.ChipConfiguration;
|
||||
import com.hootsuite.nachos.NachoTextView;
|
||||
import com.hootsuite.nachos.chip.Chip;
|
||||
import com.hootsuite.nachos.chip.ChipInfo;
|
||||
import com.hootsuite.nachos.chip.ChipSpan;
|
||||
import com.hootsuite.nachos.chip.ChipSpanChipCreator;
|
||||
import com.hootsuite.nachos.tokenizer.SpanChipTokenizer;
|
||||
import com.hootsuite.nachos.validator.IllegalCharacterIdentifier;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesComposeActivityBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Teacher;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
public class MessagesComposeActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "MessageCompose";
|
||||
private App app;
|
||||
private MessagesComposeActivityBinding b;
|
||||
private List<Teacher> teachers = new ArrayList<>();
|
||||
private ActionBar actionBar;
|
||||
private MessagesComposeInfo composeInfo;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
app = (App)getApplication();
|
||||
setTheme(Themes.INSTANCE.getAppTheme());
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.messages_compose_activity, null, false);
|
||||
setContentView(b.getRoot());
|
||||
|
||||
composeInfo = Edziennik.getApi(app, app.profile.getLoginStoreType()).getComposeInfo(app.profile);
|
||||
|
||||
Toolbar toolbar = b.toolbar;
|
||||
setSupportActionBar(toolbar);
|
||||
actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setTitle(R.string.messages_compose_title);
|
||||
}
|
||||
|
||||
List<Teacher> categories = new ArrayList<>();
|
||||
for (int i = 0; i < 11; i++) {
|
||||
categories.add(new Teacher(-1, -1*i, Teacher.typeString(this, i), ""));
|
||||
}
|
||||
|
||||
Edziennik.getApi(app, app.profile.getLoginStoreType()).getRecipientList(this, new SyncCallback() {
|
||||
@Override public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) { }
|
||||
@Override public void onSuccess(Context activityContext, ProfileFull profileFull) { }
|
||||
@Override public void onProgress(int progressStep) { }
|
||||
@Override public void onActionStarted(int stringResId) { }
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
new Handler(activityContext.getMainLooper()).post(() -> {
|
||||
app.apiEdziennik.guiShowErrorDialog(MessagesComposeActivity.this, error, R.string.messages_recipient_list_download_error);
|
||||
});
|
||||
}
|
||||
}, app.profile, teacherList -> {
|
||||
teachers.clear();
|
||||
for (Teacher teacher: teacherList) {
|
||||
if (teacher.loginId != null)
|
||||
teachers.add(teacher);
|
||||
}
|
||||
teachers.addAll(categories);
|
||||
MessagesComposeSuggestionAdapter adapter = new MessagesComposeSuggestionAdapter(this, teachers);
|
||||
//ArrayAdapter<Teacher> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, teachers);
|
||||
b.nachoTextView.setAdapter(adapter);
|
||||
});
|
||||
/*app.db.teacherDao().getAllTeachers(App.profileId).observe(this, teachers -> {
|
||||
|
||||
});*/
|
||||
|
||||
/*int[][] states = new int[][] {
|
||||
new int[] {}
|
||||
};
|
||||
int[] colors = new int[] {
|
||||
getResources().getColor(ThemeUtils.getChipColorRes())
|
||||
};*/
|
||||
//ColorStateList chipStateList = new ColorStateList(states, colors);
|
||||
|
||||
b.nachoTextView.setChipTokenizer(new SpanChipTokenizer<>(this, new ChipSpanChipCreator() {
|
||||
@Override
|
||||
public ChipSpan createChip(@NonNull Context context, @NonNull CharSequence text, Object data) {
|
||||
Teacher teacher = (Teacher) data;
|
||||
if (teacher.id <= 0) {
|
||||
int type = (int) (teacher.id * -1);
|
||||
List<Teacher> category = new ArrayList<>();
|
||||
List<String> categoryNames = new ArrayList<>();
|
||||
for (Teacher teacher1: teachers) {
|
||||
if (teacher1.isType(type)) {
|
||||
category.add(teacher1);
|
||||
categoryNames.add(teacher1.getFullName());
|
||||
}
|
||||
}
|
||||
new MaterialDialog.Builder(MessagesComposeActivity.this)
|
||||
.title(R.string.messages_compose_recipients_title)
|
||||
.content(getString(R.string.messages_compose_recipients_text_format, Teacher.typeString(MessagesComposeActivity.this, type)))
|
||||
.items(categoryNames)
|
||||
.itemsCallbackMultiChoice(null, ((dialog, which, text1) -> {
|
||||
List<ChipInfo> chipInfoList = new ArrayList<>();
|
||||
for (int index: which) {
|
||||
Teacher selected = category.get(index);
|
||||
selected.image = MessagesUtils.getProfileImage(48, 24, 16, 12, 1, selected.getFullName());
|
||||
chipInfoList.add(new ChipInfo(selected.getFullName(), selected));
|
||||
}
|
||||
b.nachoTextView.addTextWithChips(chipInfoList);
|
||||
return true;
|
||||
}))
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.show();
|
||||
return null;
|
||||
}
|
||||
ChipSpan chipSpan = new ChipSpan(context, text, new BitmapDrawable(context.getResources(), teacher.image), teacher);
|
||||
chipSpan.setIconBackgroundColor(Colors.stringToMaterialColor(teacher.getFullName()));
|
||||
return chipSpan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChip(@NonNull ChipSpan chip, @NonNull ChipConfiguration chipConfiguration) {
|
||||
super.configureChip(chip, chipConfiguration);
|
||||
//chip.setBackgroundColor(chipStateList);
|
||||
chip.setTextColor(Themes.INSTANCE.getPrimaryTextColor(MessagesComposeActivity.this));
|
||||
}
|
||||
}, ChipSpan.class));
|
||||
|
||||
|
||||
b.nachoTextView.setIllegalCharacterIdentifier(new IllegalCharacterIdentifier() {
|
||||
@Override
|
||||
public boolean isCharacterIllegal(Character c) {
|
||||
return c.toString().matches("[\\n;:_ ]");
|
||||
}
|
||||
});
|
||||
//b.nachoTextView.addChipTerminator('\n', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_ALL);
|
||||
//b.nachoTextView.addChipTerminator(' ', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_TO_TERMINATOR);
|
||||
//b.nachoTextView.addChipTerminator(';', ChipTerminatorHandler.BEHAVIOR_CHIPIFY_CURRENT_TOKEN);
|
||||
//b.nachoTextView.setNachoValidator(new ChipifyingNachoValidator());
|
||||
//b.nachoTextView.enableEditChipOnTouch(false, false);
|
||||
//b.nachoTextView.disableEditChipOnTouch();
|
||||
b.nachoTextView.setOnChipClickListener(new NachoTextView.OnChipClickListener() {
|
||||
@Override
|
||||
public void onChipClick(Chip chip, MotionEvent motionEvent) {
|
||||
Toast.makeText(app, "onChipClick: " + chip.getText(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
b.nachoTextView.setOnChipRemoveListener(new NachoTextView.OnChipRemoveListener() {
|
||||
@Override
|
||||
public void onChipRemove(Chip chip) {
|
||||
Log.d(TAG, "onChipRemoved: " + chip.getText());
|
||||
b.nachoTextView.setSelection(b.nachoTextView.getText().length());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_compose, menu);
|
||||
|
||||
menu.findItem(R.id.action_send).setIcon(
|
||||
new IconicsDrawable(this, CommunityMaterial.Icon2.cmd_send)
|
||||
.actionBar()
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(20))
|
||||
);
|
||||
menu.findItem(R.id.action_attachment).setIcon(
|
||||
new IconicsDrawable(this, CommunityMaterial.Icon.cmd_attachment)
|
||||
.actionBar()
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(20))
|
||||
);
|
||||
menu.findItem(R.id.action_attachment).setVisible(composeInfo.maxAttachmentNumber != 0);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
public class MessagesComposeInfo {
|
||||
/**
|
||||
* 0 means no attachments.
|
||||
* -1 means unlimited number.
|
||||
*/
|
||||
public int maxAttachmentNumber = 0;
|
||||
/**
|
||||
* -1 means unlimited size.
|
||||
*/
|
||||
public long attachmentSizeLimit = 0;
|
||||
/**
|
||||
* -1 means unlimited length.
|
||||
*/
|
||||
public int maxSubjectLength = -1;
|
||||
/**
|
||||
* -1 means unlimited length.
|
||||
*/
|
||||
public int maxBodyLength = -1;
|
||||
|
||||
public MessagesComposeInfo(int maxAttachmentNumber, long attachmentSizeLimit, int maxSubjectLength, int maxBodyLength) {
|
||||
this.maxAttachmentNumber = maxAttachmentNumber;
|
||||
this.attachmentSizeLimit = attachmentSizeLimit;
|
||||
this.maxSubjectLength = maxSubjectLength;
|
||||
this.maxBodyLength = maxBodyLength;
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Filter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Teacher;
|
||||
|
||||
public class MessagesComposeSuggestionAdapter extends ArrayAdapter<Teacher> {
|
||||
|
||||
private Context context;
|
||||
private List<Teacher> teacherList;
|
||||
private ArrayList<Teacher> originalList = null;
|
||||
private ArrayFilter mFilter;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
MessagesComposeSuggestionAdapter(@NonNull Context context, List<Teacher> teacherList) {
|
||||
super(context, 0, teacherList);
|
||||
this.context = context;
|
||||
this.teacherList = teacherList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
View listItem = convertView;
|
||||
if(listItem == null)
|
||||
listItem = LayoutInflater.from(context).inflate(R.layout.messages_compose_suggestion_item, parent, false);
|
||||
|
||||
Teacher teacher = teacherList.get(position);
|
||||
|
||||
TextView name = listItem.findViewById(R.id.name);
|
||||
TextView type = listItem.findViewById(R.id.type);
|
||||
ImageView image = listItem.findViewById(R.id.image);
|
||||
|
||||
teacher.image = MessagesUtils.getProfileImage(48, 24, 16, 12, 1, teacher.getFullName());
|
||||
|
||||
if (teacher.id <= 0) {
|
||||
name.setText(Teacher.typeString(context, (int) (teacher.id * -1)));
|
||||
type.setText(R.string.teachers_browse_category);
|
||||
image.setImageBitmap(null);
|
||||
}
|
||||
else {
|
||||
if (teacher.displayName == null)
|
||||
name.setText(teacher.getFullName());
|
||||
else
|
||||
name.setText(Html.fromHtml(teacher.displayName));
|
||||
type.setText(teacher.getType(context));
|
||||
image.setImageBitmap(teacher.image);
|
||||
}
|
||||
|
||||
return listItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return teacherList.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Teacher getItem(int position) {
|
||||
return teacherList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(@Nullable Teacher item) {
|
||||
return teacherList.indexOf(item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
if (mFilter == null) {
|
||||
mFilter = new ArrayFilter();
|
||||
}
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
private class TeacherWeighted extends Teacher {
|
||||
public int weight;
|
||||
|
||||
public TeacherWeighted(Teacher teacher, int weight) {
|
||||
super(teacher.profileId, teacher.id, teacher.name, teacher.surname, teacher.loginId);
|
||||
this.weight = weight;
|
||||
this.image = teacher.image;
|
||||
this.type = teacher.type;
|
||||
this.typeDescription = teacher.typeDescription;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFullName();
|
||||
}
|
||||
}
|
||||
private Comparator<? super Teacher> comparator = (o1, o2) -> ((TeacherWeighted) o1).weight - ((TeacherWeighted) o2).weight;
|
||||
|
||||
private class ArrayFilter extends Filter {
|
||||
@Override
|
||||
protected FilterResults performFiltering(CharSequence prefix) {
|
||||
final FilterResults results = new FilterResults();
|
||||
|
||||
if (originalList == null) {
|
||||
synchronized (mLock) {
|
||||
originalList = new ArrayList<>(teacherList);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix == null || prefix.length() == 0) {
|
||||
ArrayList<Teacher> list;
|
||||
synchronized (mLock) {
|
||||
list = new ArrayList<>(originalList);
|
||||
}
|
||||
results.values = list;
|
||||
results.count = list.size();
|
||||
} else {
|
||||
String prefixString = prefix.toString().toLowerCase();
|
||||
|
||||
ArrayList<Teacher> values;
|
||||
synchronized (mLock) {
|
||||
values = new ArrayList<>(originalList);
|
||||
}
|
||||
|
||||
int count = values.size();
|
||||
ArrayList<Teacher> newValues = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Teacher teacher = values.get(i);
|
||||
String teacherFullName = teacher.getFullName().toLowerCase();
|
||||
teacher.displayName = teacherFullName.replace(prefixString, "<b>"+prefixString+"</b>");
|
||||
|
||||
// First match against the whole, non-splitted value
|
||||
boolean found = false;
|
||||
if (teacherFullName.startsWith(prefixString)) {
|
||||
newValues.add(new TeacherWeighted(teacher, 1));
|
||||
found = true;
|
||||
} else {
|
||||
// check if prefix matches any of the words
|
||||
String[] words = teacherFullName.split(" ");
|
||||
for (String word : words) {
|
||||
if (word.startsWith(prefixString)) {
|
||||
newValues.add(new TeacherWeighted(teacher, 2));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// finally check if the prefix matches any part of the name
|
||||
if (!found && teacherFullName.contains(prefixString)) {
|
||||
newValues.add(new TeacherWeighted(teacher, 3));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Collections.sort(newValues, comparator);
|
||||
|
||||
results.values = newValues;
|
||||
results.count = newValues.size();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||
//noinspection unchecked
|
||||
teacherList = (List<Teacher>) results.values;
|
||||
if (results.count > 0) {
|
||||
notifyDataSetChanged();
|
||||
} else {
|
||||
notifyDataSetInvalidated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,676 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.ThumbnailUtils;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.IIcon;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.theartofdev.edmodo.cropper.CropImage;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import im.wangchao.mhttp.Response;
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesDetailsBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageRecipientFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.view.Gravity.CENTER_VERTICAL;
|
||||
import static android.view.Gravity.END;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getResizedBitmap;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getStringFromFile;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.readableFileSize;
|
||||
|
||||
public class MessagesDetailsFragment extends Fragment {
|
||||
private long messageId = -1;
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private MessagesDetailsBinding b = null;
|
||||
|
||||
private MessageFull message;
|
||||
|
||||
private List<Attachment> attachmentList = new ArrayList<>();
|
||||
|
||||
@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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.messages_details, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (getArguments() != null)
|
||||
messageId = getArguments().getLong("messageId", -1);
|
||||
|
||||
b.messageContent.setVisibility(View.GONE);
|
||||
|
||||
if (messageId != -1) {
|
||||
AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
MessageFull messageRaw = app.db.messageDao().getById(App.profileId, messageId);
|
||||
Edziennik.getApi(app, app.profile.getLoginStoreType()).getMessage(activity, new SyncCallback() {
|
||||
@Override public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) { }
|
||||
@Override public void onSuccess(Context activityContext, ProfileFull profileFull) { }
|
||||
@Override public void onProgress(int progressStep) { }
|
||||
@Override public void onActionStarted(int stringResId) { }
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
new Handler(activityContext.getMainLooper()).post(() -> {
|
||||
app.apiEdziennik.guiShowErrorDialog(activity, error, R.string.messages_download_error);
|
||||
});
|
||||
}
|
||||
}, app.profile, messageRaw, messageFull -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
message = messageFull;
|
||||
if (message.body == null) {
|
||||
return;
|
||||
}
|
||||
b.messageBody.setText(Html.fromHtml(message.body.replaceAll("\\[META:[A-z0-9]+;[0-9-]+]", "")));
|
||||
b.progress.setVisibility(View.GONE);
|
||||
Anim.fadeIn(b.messageContent, 200, null);
|
||||
|
||||
MessagesFragment.Companion.setPageSelection(Math.min(message.type, 1));
|
||||
|
||||
MessagesUtils.MessageInfo messageInfo = MessagesUtils.getMessageInfo(app, message, 40, 20, 14, 10);
|
||||
b.messageProfileBackground.setImageBitmap(messageInfo.profileImage);
|
||||
b.messageSender.setText(messageInfo.profileName);
|
||||
|
||||
b.messageSubject.setText(message.subject);
|
||||
b.messageDate.setText(getString(R.string.messages_date_time_format, Date.fromMillis(message.addedDate).getFormattedStringShort(), Time.fromMillis(message.addedDate).getStringHM()));
|
||||
|
||||
StringBuilder messageRecipients = new StringBuilder("<ul>");
|
||||
for (MessageRecipientFull recipient: message.recipients) {
|
||||
if (recipient.readDate == -1) messageRecipients.append(getString(
|
||||
R.string.messages_recipients_list_unknown_state_format,
|
||||
recipient.fullName
|
||||
));
|
||||
else if (recipient.readDate == 0) messageRecipients.append(getString(
|
||||
R.string.messages_recipients_list_unread_format,
|
||||
recipient.fullName
|
||||
));
|
||||
else if (recipient.readDate == 1) messageRecipients.append(getString(
|
||||
R.string.messages_recipients_list_read_unknown_date_format,
|
||||
recipient.fullName
|
||||
));
|
||||
else messageRecipients.append(getString(
|
||||
R.string.messages_recipients_list_read_format,
|
||||
recipient.fullName,
|
||||
Date.fromMillis(recipient.readDate).getFormattedString(),
|
||||
Time.fromMillis(recipient.readDate).getStringHM()
|
||||
));
|
||||
}
|
||||
messageRecipients.append("</ul>");
|
||||
b.messageRecipients.setText(Html.fromHtml(messageRecipients.toString()));
|
||||
|
||||
if (message.attachmentIds != null) {
|
||||
// there are some attachments: attachmentIds, attachmentNames, attachmentSizes
|
||||
ViewGroup insertPoint = b.messageAttachments;
|
||||
|
||||
FrameLayout.LayoutParams chipLayoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
chipLayoutParams.setMargins(0, Utils.dpToPx(8), 0, Utils.dpToPx(8));
|
||||
|
||||
FrameLayout.LayoutParams progressLayoutParams = new FrameLayout.LayoutParams(Utils.dpToPx(18), Utils.dpToPx(18));
|
||||
progressLayoutParams.setMargins(Utils.dpToPx(8), 0, Utils.dpToPx(8), 0);
|
||||
progressLayoutParams.gravity = END | CENTER_VERTICAL;
|
||||
|
||||
// CREATE VIEWS AND AN OBJECT FOR EVERY ATTACHMENT
|
||||
|
||||
int attachmentIndex = 0;
|
||||
for (String attachmentName: message.attachmentNames) {
|
||||
long messageId = message.id;
|
||||
long attachmentId = message.attachmentIds.get(attachmentIndex);
|
||||
long attachmentSize = message.attachmentSizes.get(attachmentIndex);
|
||||
// create the parent
|
||||
FrameLayout attachmentLayout = new FrameLayout(b.getRoot().getContext());
|
||||
|
||||
Chip attachmentChip = new Chip(attachmentLayout.getContext());
|
||||
//attachmentChip.setChipBackgroundColorResource(ThemeUtils.getChipColorRes());
|
||||
attachmentChip.setLayoutParams(chipLayoutParams);
|
||||
attachmentChip.setHeight(Utils.dpToPx(40));
|
||||
// show the file size or not
|
||||
if (attachmentSize == -1)
|
||||
attachmentChip.setText(getString(R.string.messages_attachment_no_size_format, attachmentName));
|
||||
else
|
||||
attachmentChip.setText(getString(R.string.messages_attachment_format, attachmentName, readableFileSize(attachmentSize)));
|
||||
attachmentChip.setEllipsize(TextUtils.TruncateAt.MIDDLE);
|
||||
// create an icon for the attachment
|
||||
IIcon icon = CommunityMaterial.Icon.cmd_file;
|
||||
switch (Utils.getExtensionFromFileName(attachmentName)) {
|
||||
case "txt":
|
||||
icon = CommunityMaterial.Icon.cmd_file_document;
|
||||
break;
|
||||
case "doc":
|
||||
case "docx":
|
||||
case "odt":
|
||||
case "rtf":
|
||||
icon = CommunityMaterial.Icon.cmd_file_word;
|
||||
break;
|
||||
case "xls":
|
||||
case "xlsx":
|
||||
case "ods":
|
||||
icon = CommunityMaterial.Icon.cmd_file_excel;
|
||||
break;
|
||||
case "ppt":
|
||||
case "pptx":
|
||||
case "odp":
|
||||
icon = CommunityMaterial.Icon.cmd_file_powerpoint;
|
||||
break;
|
||||
case "pdf":
|
||||
icon = CommunityMaterial.Icon.cmd_file_pdf;
|
||||
break;
|
||||
case "mp3":
|
||||
case "wav":
|
||||
case "aac":
|
||||
icon = CommunityMaterial.Icon.cmd_file_music;
|
||||
break;
|
||||
case "mp4":
|
||||
case "avi":
|
||||
case "3gp":
|
||||
case "mkv":
|
||||
case "flv":
|
||||
icon = CommunityMaterial.Icon.cmd_file_video;
|
||||
break;
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
case "png":
|
||||
case "bmp":
|
||||
case "gif":
|
||||
icon = CommunityMaterial.Icon.cmd_file_image;
|
||||
break;
|
||||
case "zip":
|
||||
case "rar":
|
||||
case "tar":
|
||||
case "7z":
|
||||
icon = CommunityMaterial.Icon.cmd_file_lock;
|
||||
break;
|
||||
}
|
||||
attachmentChip.setChipIcon(new IconicsDrawable(activity).color(IconicsColor.colorRes(R.color.colorPrimary)).icon(icon).size(IconicsSize.dp(26)));
|
||||
attachmentChip.setCloseIcon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_check).size(IconicsSize.dp(18)).color(IconicsColor.colorInt(Utils.getAttr(activity, android.R.attr.textColorPrimary))));
|
||||
attachmentChip.setCloseIconVisible(false);
|
||||
// set the object's index in the attachmentList as the tag
|
||||
attachmentChip.setTag(attachmentIndex);
|
||||
attachmentChip.setOnClickListener(v -> {
|
||||
if (v.getTag() instanceof Integer) {
|
||||
downloadAttachment((Integer) v.getTag());
|
||||
}
|
||||
});
|
||||
attachmentLayout.addView(attachmentChip);
|
||||
|
||||
ProgressBar attachmentProgress = new ProgressBar(attachmentLayout.getContext());
|
||||
attachmentProgress.setLayoutParams(progressLayoutParams);
|
||||
attachmentProgress.setVisibility(View.GONE);
|
||||
attachmentLayout.addView(attachmentProgress);
|
||||
|
||||
insertPoint.addView(attachmentLayout);
|
||||
// create an object and add to the list
|
||||
Attachment a = new Attachment(App.profileId, messageId, attachmentId, attachmentName, attachmentSize, attachmentLayout, attachmentChip, attachmentProgress);
|
||||
attachmentList.add(a);
|
||||
// check if the file is already downloaded. Show the check icon if necessary and set `downloaded` to true.
|
||||
checkAttachment(a);
|
||||
|
||||
attachmentIndex++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no attachments found
|
||||
b.messageAttachmentsTitle.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// click to expand subject and sender
|
||||
b.messageSubject.setOnClickListener(v -> {
|
||||
if (b.messageSubject.getMaxLines() == 2) {
|
||||
b.messageSubject.setMaxLines(30);
|
||||
}
|
||||
else {
|
||||
b.messageSubject.setMaxLines(2);
|
||||
}
|
||||
});
|
||||
b.messageSender.setOnClickListener(v -> {
|
||||
if (b.messageSender.getMaxLines() == 3) {
|
||||
b.messageSender.setMaxLines(30);
|
||||
}
|
||||
else {
|
||||
b.messageSender.setMaxLines(3);
|
||||
}
|
||||
});
|
||||
|
||||
// message close button
|
||||
b.messageClose.setImageDrawable(new IconicsDrawable(activity).icon(CommunityMaterial.Icon2.cmd_window_close).color(IconicsColor.colorInt(Utils.getAttr(activity, android.R.attr.textColorSecondary))).size(IconicsSize.dp(12)));
|
||||
b.messageClose.setOnClickListener(v -> {
|
||||
activity.navigateUp();
|
||||
});
|
||||
|
||||
// enter, exit transitions
|
||||
//setExitTransition(new Fade());
|
||||
|
||||
/*View content = b.getRoot();
|
||||
content.setAlpha(0f);
|
||||
|
||||
ValueAnimator animator = ObjectAnimator.ofFloat(content, View.ALPHA, 0f, 1f);
|
||||
animator.setStartDelay(50);
|
||||
animator.setDuration(150);
|
||||
animator.start();*/
|
||||
}
|
||||
|
||||
private void checkAttachment(Attachment a) {
|
||||
|
||||
File storageDir = Environment.getExternalStoragePublicDirectory("Szkolny.eu");
|
||||
storageDir.mkdirs();
|
||||
|
||||
File attachmentDataFile = new File(storageDir, "."+a.profileId+"_"+a.messageId+"_"+a.attachmentId);
|
||||
if (attachmentDataFile.exists()) {
|
||||
try {
|
||||
String attachmentFileName = getStringFromFile(attachmentDataFile);
|
||||
File attachmentFile = new File(attachmentFileName);
|
||||
if (attachmentFile.exists()) {
|
||||
a.downloaded = attachmentFileName;
|
||||
a.chip.setCloseIconVisible(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
app.apiEdziennik.guiReportException(activity, 355, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadAttachment(int index) {
|
||||
Attachment a = attachmentList.get(index);
|
||||
|
||||
if (a.downloaded != null) {
|
||||
Utils.openFile(activity, new File(a.downloaded));
|
||||
return;
|
||||
}
|
||||
|
||||
a.chip.setEnabled(false);
|
||||
a.chip.setTextColor(Themes.INSTANCE.getSecondaryTextColor(activity));
|
||||
a.progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
File storageDir = Utils.getStorageDir();
|
||||
|
||||
Edziennik.getApi(app, app.profile.getLoginStoreType()).getAttachment(activity, new SyncCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profileFull) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
new Handler(activityContext.getMainLooper()).post(() -> {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.chip.setEnabled(true);
|
||||
a.chip.setTextColor(Themes.INSTANCE.getPrimaryTextColor(activity));
|
||||
a.chip.setCloseIconVisible(false);
|
||||
app.apiEdziennik.guiShowErrorDialog(activity, error, R.string.messages_attachment_cannot_download);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
|
||||
}
|
||||
}, app.profile, message, a.attachmentId, builder ->
|
||||
builder.callbackThreadMode(im.wangchao.mhttp.ThreadMode.SENDING)
|
||||
.callback(new FileCallbackHandler(new File(storageDir, a.attachmentName)) {
|
||||
@Override
|
||||
public void onSuccess(File file, Response response) {
|
||||
AttachmentEvent event = new AttachmentEvent();
|
||||
event.profileId = a.profileId;
|
||||
event.messageId = a.messageId;
|
||||
event.attachmentId = a.attachmentId;
|
||||
event.eventType = AttachmentEvent.TYPE_FINISHED;
|
||||
event.fileName = file.getAbsolutePath();
|
||||
|
||||
try {
|
||||
File attachmentDataFile = new File(Utils.getStorageDir(), "."+event.profileId+"_"+event.messageId+"_"+event.attachmentId);
|
||||
Utils.writeStringToFile(attachmentDataFile, event.fileName);
|
||||
} catch (IOException e) {
|
||||
event.eventType = AttachmentEvent.TYPE_ERROR;
|
||||
event.exception = e;
|
||||
}
|
||||
finally {
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Response response, Throwable throwable) {
|
||||
AttachmentEvent event = new AttachmentEvent();
|
||||
event.profileId = a.profileId;
|
||||
event.messageId = a.messageId;
|
||||
event.attachmentId = a.attachmentId;
|
||||
event.eventType = AttachmentEvent.TYPE_ERROR;
|
||||
event.exception = new Exception(throwable);
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(long bytesWritten, long bytesTotal) {
|
||||
AttachmentEvent event = new AttachmentEvent();
|
||||
event.profileId = a.profileId;
|
||||
event.messageId = a.messageId;
|
||||
event.attachmentId = a.attachmentId;
|
||||
event.eventType = AttachmentEvent.TYPE_PROGRESS;
|
||||
event.progress = (float)bytesWritten / (float)bytesTotal * 100.0f;
|
||||
EventBus.getDefault().post(event);
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue());
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.POSTING)
|
||||
public void downloadAttachmentEvent(AttachmentEvent event) {
|
||||
try {
|
||||
for (Attachment a: attachmentList) {
|
||||
if (a.profileId == event.profileId
|
||||
&& a.messageId == event.messageId
|
||||
&& a.attachmentId == event.attachmentId) {
|
||||
if (event.eventType == AttachmentEvent.TYPE_PROGRESS) {
|
||||
// show downloading progress
|
||||
a.chip.setText(getString(R.string.messages_attachment_downloading_format, a.attachmentName, Math.round(event.progress)));
|
||||
}
|
||||
else if (event.eventType == AttachmentEvent.TYPE_FINISHED) {
|
||||
// save the downloaded file name
|
||||
a.downloaded = event.fileName;
|
||||
// set the correct name (and size)
|
||||
if (a.attachmentSize == -1)
|
||||
a.chip.setText(getString(R.string.messages_attachment_no_size_format, a.attachmentName));
|
||||
else
|
||||
a.chip.setText(getString(R.string.messages_attachment_format, a.attachmentName, readableFileSize(a.attachmentSize)));
|
||||
// hide the progress bar and show a tick icon
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.chip.setEnabled(true);
|
||||
a.chip.setTextColor(Themes.INSTANCE.getPrimaryTextColor(activity));
|
||||
a.chip.setCloseIconVisible(true);
|
||||
// open the file
|
||||
Utils.openFile(activity, new File(a.downloaded));
|
||||
}
|
||||
else if (event.eventType == AttachmentEvent.TYPE_ERROR) {
|
||||
a.progressBar.setVisibility(View.GONE);
|
||||
a.chip.setEnabled(true);
|
||||
a.chip.setTextColor(Themes.INSTANCE.getPrimaryTextColor(activity));
|
||||
a.chip.setCloseIconVisible(false);
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.messages_attachment_cannot_download)
|
||||
.content(R.string.messages_attachment_cannot_download_text)
|
||||
.positiveText(R.string.ok)
|
||||
.neutralColor(R.string.report)
|
||||
.onNeutral((dialog, which) -> {
|
||||
app.apiEdziennik.guiReportException(activity, 433, event.exception);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
app.apiEdziennik.guiReportException(activity, 425, e);
|
||||
}
|
||||
}
|
||||
|
||||
private class Attachment {
|
||||
int profileId;
|
||||
long messageId;
|
||||
long attachmentId;
|
||||
String attachmentName;
|
||||
long attachmentSize;
|
||||
FrameLayout parent;
|
||||
Chip chip;
|
||||
ProgressBar progressBar;
|
||||
/**
|
||||
* An absolute path of the downloaded file. {@code null} if not downloaded yet.
|
||||
*/
|
||||
String downloaded = null;
|
||||
|
||||
public Attachment(int profileId, long messageId, long attachmentId, String attachmentName, long attachmentSize, FrameLayout parent, Chip chip, ProgressBar progressBar) {
|
||||
this.profileId = profileId;
|
||||
this.messageId = messageId;
|
||||
this.attachmentId = attachmentId;
|
||||
this.attachmentName = attachmentName;
|
||||
this.attachmentSize = attachmentSize;
|
||||
this.parent = parent;
|
||||
this.chip = chip;
|
||||
this.progressBar = progressBar;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AttachmentEvent {
|
||||
public int profileId;
|
||||
public long messageId;
|
||||
public long attachmentId;
|
||||
|
||||
public static final int TYPE_PROGRESS = 0;
|
||||
public static final int TYPE_FINISHED = 1;
|
||||
public static final int TYPE_ERROR = 2;
|
||||
public int eventType = TYPE_PROGRESS;
|
||||
|
||||
public float progress = 0.0f;
|
||||
public String fileName = null;
|
||||
public Exception exception = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||
CropImage.ActivityResult result = CropImage.getActivityResult(data);
|
||||
|
||||
Uri uri = result.getUri();
|
||||
|
||||
File photoFile = new File(uri.getPath());
|
||||
File destFile = new File(getContext().getFilesDir(),"teacher_"+message.senderId+".jpg");
|
||||
if (destFile.exists()) {
|
||||
destFile.delete();
|
||||
destFile = new File(getContext().getFilesDir(),"teacher_"+message.senderId+".jpg");
|
||||
}
|
||||
|
||||
|
||||
if (result.getCropRect().width() > 512) {
|
||||
Bitmap bigImage = BitmapFactory.decodeFile(uri.getPath());
|
||||
Bitmap smallImage = getResizedBitmap(bigImage, 512, 512);
|
||||
try (FileOutputStream out = new FileOutputStream(destFile)) {
|
||||
smallImage.compress(Bitmap.CompressFormat.JPEG, 80, out); // bmp is your Bitmap instance
|
||||
// PNG is a lossless format, the compression factor (100) is ignored
|
||||
Bitmap profileImage;
|
||||
profileImage = BitmapFactory.decodeFile(destFile.getAbsolutePath());
|
||||
profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight()));
|
||||
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(app.getResources(), profileImage);
|
||||
roundDrawable.setCircular(true);
|
||||
b.messageProfileImage.setImageDrawable(roundDrawable);
|
||||
if (app.appConfig.teacherImages == null) {
|
||||
app.appConfig.teacherImages = new HashMap<>();
|
||||
}
|
||||
app.appConfig.teacherImages.put(message.senderId, true);
|
||||
app.saveConfig("teacherImages");
|
||||
if (photoFile.exists()) {
|
||||
photoFile.delete();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (photoFile.renameTo(destFile)) {
|
||||
// success
|
||||
Bitmap profileImage;
|
||||
profileImage = BitmapFactory.decodeFile(destFile.getAbsolutePath());
|
||||
profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight()));
|
||||
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(app.getResources(), profileImage);
|
||||
roundDrawable.setCircular(true);
|
||||
b.messageProfileImage.setImageDrawable(roundDrawable);
|
||||
if (app.appConfig.teacherImages == null) {
|
||||
app.appConfig.teacherImages = new HashMap<>();
|
||||
}
|
||||
app.appConfig.teacherImages.put(message.senderId, true);
|
||||
app.saveConfig("teacherImages");
|
||||
}
|
||||
else {
|
||||
// not this time
|
||||
Toast.makeText(app, R.string.error_occured, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (message.type == TYPE_RECEIVED) {
|
||||
b.messageSender.setText(message.senderFullName);
|
||||
}
|
||||
else if (message.type == TYPE_SENT && message.recipients != null && message.recipients.size() > 0) {
|
||||
StringBuilder senderText = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (MessageRecipientFull recipient: message.recipients) {
|
||||
if (!first) {
|
||||
senderText.append(", ");
|
||||
}
|
||||
first = false;
|
||||
senderText.append(recipient.fullName);
|
||||
}
|
||||
b.messageSender.setText(senderText.toString());
|
||||
}
|
||||
|
||||
if (message.type == TYPE_RECEIVED) {
|
||||
if (app.appConfig.teacherImages != null && app.appConfig.teacherImages.size() > 0 && app.appConfig.teacherImages.containsKey(message.senderId)) {
|
||||
Bitmap profileImage;
|
||||
profileImage = BitmapFactory.decodeFile(app.getFilesDir().getAbsolutePath()+"/teacher_"+message.senderId+".jpg");
|
||||
profileImage = ThumbnailUtils.extractThumbnail(profileImage, Math.min(profileImage.getWidth(), profileImage.getHeight()), Math.min(profileImage.getWidth(), profileImage.getHeight()));
|
||||
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(app.getResources(), profileImage);
|
||||
roundDrawable.setCircular(true);
|
||||
b.messageProfileImage.setImageDrawable(roundDrawable);
|
||||
}
|
||||
else {
|
||||
int color = Colors.stringToMaterialColor(message.senderFullName);
|
||||
b.messageProfileBackground.getDrawable().setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
|
||||
b.messageProfileName.setTextColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
if (message.senderFullName != null) {
|
||||
String[] nameParts = message.senderFullName.split(" ");
|
||||
b.messageProfileName.setText(nameParts[0].toUpperCase().charAt(0) + "" + nameParts[1].toUpperCase().charAt(0));
|
||||
}
|
||||
else {
|
||||
b.messageProfileName.setText("N");
|
||||
}
|
||||
}
|
||||
|
||||
View.OnClickListener onClickListener = v -> new MaterialDialog.Builder(activity)
|
||||
.title(R.string.settings_profile_change_title)
|
||||
.items(
|
||||
getString(R.string.settings_profile_change_image),
|
||||
getString(R.string.settings_profile_remove_image)
|
||||
)
|
||||
.itemsCallback((dialog, itemView, position, text) -> {
|
||||
switch (position) {
|
||||
case 0:
|
||||
CropImage.activity()
|
||||
.setAspectRatio(1, 1)
|
||||
//.setMaxCropResultSize(512, 512)
|
||||
.setCropShape(CropImageView.CropShape.OVAL)
|
||||
.setGuidelines(CropImageView.Guidelines.ON)
|
||||
.start(activity, MessagesDetailsFragment.this);
|
||||
break;
|
||||
case 1:
|
||||
if (app.appConfig.teacherImages != null) {
|
||||
app.appConfig.teacherImages.remove(message.senderId);
|
||||
app.saveConfig("teacherImages");
|
||||
}
|
||||
break;
|
||||
}
|
||||
})
|
||||
.negativeText(R.string.cancel)
|
||||
.show();
|
||||
b.messageSender.setOnClickListener(onClickListener);
|
||||
b.messageProfileBackground.setOnClickListener(onClickListener);
|
||||
}*/
|
@ -0,0 +1,106 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentMessagesBinding
|
||||
import pl.szczodrzynski.edziennik.datamodels.Message
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import java.util.*
|
||||
|
||||
class MessagesFragment : Fragment() {
|
||||
companion object {
|
||||
var pageSelection = 0
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentMessagesBinding
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = FragmentMessagesBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
val messageId = arguments?.getLong("messageId", -1L) ?: -1L
|
||||
if (messageId != -1L) {
|
||||
val args = Bundle()
|
||||
args.putLong("messageId", messageId)
|
||||
arguments!!.remove("messageId")
|
||||
activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args)
|
||||
return
|
||||
}
|
||||
|
||||
b.viewPager.adapter = Adapter(childFragmentManager).also { adapter ->
|
||||
|
||||
adapter.addFragment(MessagesListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
args.putInt("messageType", Message.TYPE_RECEIVED)
|
||||
}
|
||||
}, getString(R.string.menu_messages_inbox))
|
||||
|
||||
adapter.addFragment(MessagesListFragment().also { fragment ->
|
||||
fragment.arguments = Bundle().also { args ->
|
||||
args.putInt("messageType", Message.TYPE_SENT)
|
||||
}
|
||||
}, getString(R.string.menu_messages_sent))
|
||||
|
||||
}
|
||||
|
||||
b.viewPager.currentItem = pageSelection
|
||||
b.viewPager.clearOnPageChangeListeners()
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
}
|
||||
})
|
||||
|
||||
b.tabLayout.setupWithViewPager(b.viewPager)
|
||||
}
|
||||
|
||||
internal class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
|
||||
private val mFragmentList = ArrayList<Fragment>()
|
||||
private val mFragmentTitleList = ArrayList<String>()
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return mFragmentList[position]
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return mFragmentList.size
|
||||
}
|
||||
|
||||
fun addFragment(fragment: Fragment, title: String) {
|
||||
mFragmentList.add(fragment)
|
||||
mFragmentTitleList.add(title)
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
return mFragmentTitleList[position]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Html;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesListBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Message;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageRecipientFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile;
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class MessagesListFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private MessagesListBinding b = null;
|
||||
|
||||
private Rect viewRect = new Rect();
|
||||
private MessagesAdapter messagesAdapter = null;
|
||||
private ViewGroup viewParent = null;
|
||||
|
||||
static final Interpolator transitionInterpolator = new FastOutSlowInInterpolator();
|
||||
static final long TRANSITION_DURATION = 300L;
|
||||
static final String TAP_POSITION = "tap_position";
|
||||
|
||||
private static int tapPosition = NO_POSITION;
|
||||
private static int topPosition = NO_POSITION;
|
||||
private static int bottomPosition = NO_POSITION;
|
||||
|
||||
private int messageType = Message.TYPE_RECEIVED;
|
||||
|
||||
@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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.messages_list, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
long messageId = -1;
|
||||
if (getArguments() != null) {
|
||||
messageId = getArguments().getLong("messageId", -1);
|
||||
}
|
||||
if (messageId != -1) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("messageId", messageId);
|
||||
getArguments().remove("messageId");
|
||||
activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args);
|
||||
return;
|
||||
}
|
||||
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_LIBRUS && app.profile.getStudentData("accountPassword", null) == null) {
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title("Wiadomości w systemie Synergia")
|
||||
.content("Moduł Wiadomości w aplikacji Szkolny.eu jest przeglądarką zasobów szkolnego konta Synergia. Z tego powodu, musisz wpisać swoje hasło do tego konta, aby móc korzystać z tej funkcji.")
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(((dialog, which) -> {
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title("Zaloguj się")
|
||||
.content(Html.fromHtml("Podaj hasło do konta Synergia z loginem <b>"+app.profile.getStudentData("accountLogin", "???")+"</b>"))
|
||||
.inputType(InputType.TYPE_TEXT_VARIATION_PASSWORD)
|
||||
.input(null, null, (dialog1, input) -> {
|
||||
app.profile.putStudentData("accountPassword", input.toString());
|
||||
Edziennik.getApi(app, app.profile.getLoginStoreType()).syncMessages(activity, new SyncCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Context activityContext, ProfileFull profileFull) {
|
||||
app.profile.putStudentData("accountPassword", input.toString());
|
||||
app.profileSaveFullAsync(profileFull);
|
||||
((MainActivity) activityContext).recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context activityContext, AppError error) {
|
||||
new Handler(activityContext.getMainLooper()).post(() -> {
|
||||
app.profile.removeStudentData("accountPassword");
|
||||
app.profileSaveFullAsync(app.profile);
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.login_failed)
|
||||
.content(R.string.login_failed_text)
|
||||
.positiveText(R.string.ok)
|
||||
.neutralText(R.string.report)
|
||||
.onNeutral(((dialog2, which1) -> {
|
||||
app.apiEdziennik.guiReportError(getActivity(), error, null);
|
||||
}))
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int progressStep) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionStarted(int stringResId) {
|
||||
|
||||
}
|
||||
}, app.profile);
|
||||
})
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.show();
|
||||
}))
|
||||
.show();
|
||||
}
|
||||
|
||||
if (getArguments() != null) {
|
||||
messageType = getArguments().getInt("messageType", Message.TYPE_RECEIVED);
|
||||
}
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(messageType, b.refreshLayout);
|
||||
});*/
|
||||
|
||||
messagesAdapter = new MessagesAdapter(app, ((parent, view1, position, id) -> {
|
||||
// TODO ANIMATION
|
||||
/*tapPosition = position;
|
||||
topPosition = ((LinearLayoutManager) b.emailList.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
|
||||
bottomPosition = ((LinearLayoutManager) b.emailList.getLayoutManager()).findLastCompletelyVisibleItemPosition();
|
||||
|
||||
view1.getGlobalVisibleRect(viewRect);
|
||||
((Transition) MessagesListFragment.this.getExitTransition()).setEpicenterCallback(new Transition.EpicenterCallback() {
|
||||
@Override
|
||||
public Rect onGetEpicenter(@NonNull Transition transition) {
|
||||
return viewRect;
|
||||
}
|
||||
});*/
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("messageId", messagesAdapter.messageList.get(position).id);
|
||||
activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args);
|
||||
|
||||
// KOD W WERSJI 2.7
|
||||
// TODO ANIMATION
|
||||
/*TransitionSet sharedElementTransition = new TransitionSet()
|
||||
.addTransition(new Fade())
|
||||
.addTransition(new ChangeBounds())
|
||||
.addTransition(new ChangeTransform())
|
||||
.addTransition(new ChangeImageTransform())
|
||||
.setDuration(TRANSITION_DURATION)
|
||||
.setInterpolator(transitionInterpolator);
|
||||
|
||||
MessagesDetailsFragment fragment = new MessagesDetailsFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("messageId", messagesAdapter.messageList.get(position).id);
|
||||
fragment.setArguments(args);
|
||||
fragment.setSharedElementEnterTransition(sharedElementTransition);
|
||||
fragment.setSharedElementReturnTransition(sharedElementTransition);*/
|
||||
|
||||
// JAKIS STARSZY KOD
|
||||
/*Intent intent = new Intent(activity, MessagesDetailsActivity.class);
|
||||
intent.putExtra("item_id", 1);
|
||||
intent.putExtra("transition_name", ViewCompat.getTransitionName(view1));
|
||||
|
||||
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
||||
activity,
|
||||
view1,
|
||||
getString(R.string.transition_name)
|
||||
);
|
||||
|
||||
TransitionManager.beginDelayedTransition((ViewGroup) view1, sharedElementTransition);
|
||||
setEnterTransition(sharedElementTransition);
|
||||
setReturnTransition(sharedElementTransition);
|
||||
setExitTransition(sharedElementTransition);
|
||||
setSharedElementEnterTransition(sharedElementTransition);
|
||||
setSharedElementReturnTransition(sharedElementTransition);
|
||||
startActivity(intent, options.toBundle());*/
|
||||
|
||||
/*activity.getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.setReorderingAllowed(true)
|
||||
.replace(R.id.fragment_container, fragment)
|
||||
.addToBackStack(null)
|
||||
.addSharedElement(view1, getString(R.string.transition_name))
|
||||
.commit();*/
|
||||
|
||||
}));
|
||||
|
||||
|
||||
//tapPosition = savedInstanceState != null ? savedInstanceState.getInt(TAP_POSITION, tapPosition) : tapPosition;
|
||||
|
||||
// May not be the best place to postpone transition. Just an example to demo how reenter transition works.
|
||||
// TODO ANIMATION
|
||||
//postponeEnterTransition();
|
||||
|
||||
viewParent = (ViewGroup) view.getParent();
|
||||
|
||||
b.emailList.setLayoutManager(new LinearLayoutManager(view.getContext()));
|
||||
b.emailList.addItemDecoration(new DividerItemDecoration(view.getContext(), LinearLayoutManager.VERTICAL));
|
||||
b.emailList.setAdapter(messagesAdapter);
|
||||
|
||||
if (messageType == Message.TYPE_RECEIVED) {
|
||||
app.db.messageDao().getReceived(App.profileId).observe(this, messageFulls -> {
|
||||
createMessageList(messageFulls);
|
||||
});
|
||||
}
|
||||
else if (messageType == Message.TYPE_DELETED) {
|
||||
app.db.messageDao().getDeleted(App.profileId).observe(this, messageFulls -> {
|
||||
createMessageList(messageFulls);
|
||||
});
|
||||
}
|
||||
else if (messageType == Message.TYPE_SENT) {
|
||||
app.db.messageDao().getSent(App.profileId).observe(this, messageFulls -> {
|
||||
AsyncTask.execute(() -> {
|
||||
List<MessageRecipientFull> messageRecipients = app.db.messageRecipientDao().getAll(App.profileId);
|
||||
List<Long> messageIds = new ArrayList<>();
|
||||
for (MessageFull messageFull: messageFulls) {
|
||||
messageIds.add(messageFull.id);
|
||||
}
|
||||
for (MessageRecipientFull messageRecipientFull: messageRecipients) {
|
||||
if (messageRecipientFull.id == -1)
|
||||
continue;
|
||||
|
||||
int index = -1;
|
||||
|
||||
int i = -1;
|
||||
for (long id: messageIds) {
|
||||
//index++;
|
||||
i++;
|
||||
if (id == messageRecipientFull.messageId) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
MessageFull messageFull = messageFulls.get(index);
|
||||
if (messageFull != null) {
|
||||
messageFull.addRecipient(messageRecipientFull);
|
||||
}
|
||||
}
|
||||
}
|
||||
activity.runOnUiThread(() -> {
|
||||
createMessageList(messageFulls);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void createMessageList(List<MessageFull> messageFulls) {
|
||||
b.progressBar.setVisibility(View.GONE);
|
||||
b.emailList.setVisibility(View.VISIBLE);
|
||||
messagesAdapter.setData(messageFulls);
|
||||
// TODO ANIMATION
|
||||
/*final ViewTreeObserver observer = viewParent.getViewTreeObserver();
|
||||
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
viewParent.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
if (getExitTransition() == null) {
|
||||
setExitTransition(new SlideExplode().setDuration(TRANSITION_DURATION).setInterpolator(transitionInterpolator));
|
||||
}
|
||||
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) b.emailList.getLayoutManager();
|
||||
View view2 = layoutManager != null ? layoutManager.findViewByPosition(tapPosition) : null;
|
||||
if (view2 != null) {
|
||||
view2.getGlobalVisibleRect(viewRect);
|
||||
((Transition) getExitTransition()).setEpicenterCallback(new Transition.EpicenterCallback() {
|
||||
@Override
|
||||
public Rect onGetEpicenter(@NonNull Transition transition) {
|
||||
return viewRect;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
d("MessagesList", "topPosition "+topPosition);
|
||||
d("MessagesList", "tapPosition "+tapPosition);
|
||||
d("MessagesList", "bottomPosition "+bottomPosition);
|
||||
if (tapPosition != NO_POSITION && layoutManager != null) {
|
||||
d("MessageList", "Scrolling");
|
||||
|
||||
if (bottomPosition > layoutManager.findLastCompletelyVisibleItemPosition()) {
|
||||
b.emailList.scrollToPosition(bottomPosition);
|
||||
}
|
||||
else if (topPosition < layoutManager.findFirstCompletelyVisibleItemPosition()) {
|
||||
b.emailList.scrollToPosition(topPosition);
|
||||
}
|
||||
else {
|
||||
b.emailList.scrollToPosition(tapPosition);
|
||||
}
|
||||
|
||||
tapPosition = NO_POSITION;
|
||||
topPosition = NO_POSITION;
|
||||
bottomPosition = NO_POSITION;
|
||||
}
|
||||
|
||||
startPostponedEnterTransition();
|
||||
return true;
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
d("MessagesList", "onSaveInstanceState position "+tapPosition);
|
||||
outState.putInt(TAP_POSITION, tapPosition);
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageRecipientFull;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Message.TYPE_DELETED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Message.TYPE_DRAFT;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Message.TYPE_RECEIVED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Message.TYPE_SENT;
|
||||
|
||||
public class MessagesUtils {
|
||||
public static class MessageInfo {
|
||||
public Bitmap profileImage;
|
||||
public String profileName;
|
||||
|
||||
public MessageInfo(Bitmap profileImage, String profileName) {
|
||||
this.profileImage = profileImage;
|
||||
this.profileName = profileName;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getInitials(String name) {
|
||||
if (name == null || name.isEmpty())
|
||||
return "";
|
||||
name = name.toUpperCase();
|
||||
String[] nameParts = name.split(" ");
|
||||
return nameParts.length <= 1 ?
|
||||
(name.length() == 0 ? "?" : name.charAt(0))+"" :
|
||||
(nameParts[0].length() == 0 ? "?" : nameParts[0].charAt(0))
|
||||
+ "" +
|
||||
(nameParts[1].length() == 0 ? "?" : nameParts[1].charAt(0));
|
||||
}
|
||||
|
||||
private static int getPaintCenter(Paint textPaint) {
|
||||
return Math.round((textPaint.descent() + textPaint.ascent()) / 2);
|
||||
}
|
||||
|
||||
public static Bitmap getProfileImage(int diameterDp, int textSizeBigDp, int textSizeMediumDp, int textSizeSmallDp, int count, String ... names) {
|
||||
float diameter = Utils.dpToPx(diameterDp);
|
||||
float textSizeBig = Utils.dpToPx(textSizeBigDp);
|
||||
float textSizeMedium = Utils.dpToPx(textSizeMediumDp);
|
||||
float textSizeSmall = Utils.dpToPx(textSizeSmallDp);
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap((int) diameter, (int) diameter, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
Paint circlePaint = new Paint();
|
||||
circlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
Paint textPaint = new Paint();
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
RectF rectF = new RectF();
|
||||
rectF.set(0, 0, diameter, diameter);
|
||||
|
||||
String name;
|
||||
int color;
|
||||
|
||||
if (count == 1) {
|
||||
name = names[0];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeBig);
|
||||
canvas.drawArc(rectF, 0, 360, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/2, diameter/2 - getPaintCenter(textPaint), textPaint);
|
||||
}
|
||||
else if (count == 2) {
|
||||
// top
|
||||
name = names[0];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeMedium);
|
||||
canvas.drawArc(rectF, 180, 180, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/2, diameter/4 - getPaintCenter(textPaint), textPaint);
|
||||
|
||||
// bottom
|
||||
name = names[1];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeMedium);
|
||||
canvas.drawArc(rectF, 0, 180, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/2, diameter/4*3 - getPaintCenter(textPaint), textPaint);
|
||||
}
|
||||
else if (count == 3) {
|
||||
// upper left
|
||||
name = names[0];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeSmall);
|
||||
canvas.drawArc(rectF, 180, 90, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/4, diameter/4 - getPaintCenter(textPaint) + diameter/32, textPaint);
|
||||
|
||||
// upper right
|
||||
name = names[1];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeSmall);
|
||||
canvas.drawArc(rectF, 270, 90, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/4*3, diameter/4 - getPaintCenter(textPaint) + diameter/32, textPaint);
|
||||
|
||||
// bottom
|
||||
name = names[2];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeMedium);
|
||||
canvas.drawArc(rectF, 0, 180, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/2, diameter/4*3 - getPaintCenter(textPaint), textPaint);
|
||||
}
|
||||
else if (count >= 4) {
|
||||
// upper left
|
||||
name = names[0];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeSmall);
|
||||
canvas.drawArc(rectF, 180, 90, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/4, diameter/4 - getPaintCenter(textPaint) + diameter/32, textPaint);
|
||||
|
||||
// upper right
|
||||
name = names[1];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeSmall);
|
||||
canvas.drawArc(rectF, 270, 90, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/4*3, diameter/4 - getPaintCenter(textPaint) + diameter/32, textPaint);
|
||||
|
||||
// bottom left
|
||||
name = names[2];
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeSmall);
|
||||
canvas.drawArc(rectF, 90, 90, true, circlePaint);
|
||||
canvas.drawText(getInitials(name), diameter/4, diameter/4*3 - getPaintCenter(textPaint) - diameter/32, textPaint);
|
||||
|
||||
// bottom right
|
||||
if (count == 4)
|
||||
name = names[3];
|
||||
if (count > 4)
|
||||
name = "...";
|
||||
circlePaint.setColor(color = Colors.stringToMaterialColor(name));
|
||||
textPaint.setColor(ColorUtils.blendARGB(Colors.legibleTextColor(color), color, 0.30f));
|
||||
textPaint.setTextSize(textSizeSmall);
|
||||
canvas.drawArc(rectF, 0, 90, true, circlePaint);
|
||||
canvas.drawText(count > 4 ? "+"+(count-3) : getInitials(name), diameter/4*3, diameter/4*3 - getPaintCenter(textPaint) - diameter/32, textPaint);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static MessageInfo getMessageInfo(App app, MessageFull message, int diameterDp, int textSizeBigDp, int textSizeMediumDp, int textSizeSmallDp) {
|
||||
Bitmap profileImage = null;
|
||||
String profileName = null;
|
||||
if (message.type == TYPE_RECEIVED || message.type == TYPE_DELETED) {
|
||||
profileName = message.senderFullName;
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 1, message.senderFullName);
|
||||
}
|
||||
else if (message.type == TYPE_SENT || message.type == TYPE_DRAFT && message.recipients != null) {
|
||||
int count = message.recipients == null ? 0 : message.recipients.size();
|
||||
if (count == 0) {
|
||||
profileName = app.getString(R.string.messages_draft_title);
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 1, "?");
|
||||
}
|
||||
else if (count == 1) {
|
||||
MessageRecipientFull recipient = message.recipients.get(0);
|
||||
profileName = recipient.fullName;
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 1, recipient.fullName);
|
||||
}
|
||||
else if (count == 2) {
|
||||
MessageRecipientFull recipient1 = message.recipients.get(0);
|
||||
MessageRecipientFull recipient2 = message.recipients.get(1);
|
||||
profileName = recipient1.fullName+", "+recipient2.fullName;
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 2, recipient1.fullName, recipient2.fullName);
|
||||
}
|
||||
else if (count == 3) {
|
||||
MessageRecipientFull recipient1 = message.recipients.get(0);
|
||||
MessageRecipientFull recipient2 = message.recipients.get(1);
|
||||
MessageRecipientFull recipient3 = message.recipients.get(2);
|
||||
profileName = recipient1.fullName+", "+recipient2.fullName+", "+recipient3.fullName;
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 3, recipient1.fullName, recipient2.fullName, recipient3.fullName);
|
||||
}
|
||||
else if (count == 4) {
|
||||
MessageRecipientFull recipient1 = message.recipients.get(0);
|
||||
MessageRecipientFull recipient2 = message.recipients.get(1);
|
||||
MessageRecipientFull recipient3 = message.recipients.get(2);
|
||||
MessageRecipientFull recipient4 = message.recipients.get(3);
|
||||
profileName = recipient1.fullName+", "+recipient2.fullName+", "+recipient3.fullName+", "+recipient4.fullName;
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 4, recipient1.fullName, recipient2.fullName, recipient3.fullName, recipient4.fullName);
|
||||
}
|
||||
else {
|
||||
MessageRecipientFull recipient1 = message.recipients.get(0);
|
||||
MessageRecipientFull recipient2 = message.recipients.get(1);
|
||||
MessageRecipientFull recipient3 = message.recipients.get(2);
|
||||
|
||||
StringBuilder senderText = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (MessageRecipientFull recipient: message.recipients) {
|
||||
if (!first) {
|
||||
senderText.append(", ");
|
||||
}
|
||||
first = false;
|
||||
senderText.append(recipient.fullName);
|
||||
}
|
||||
profileName = senderText.toString();
|
||||
|
||||
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, count, recipient1.fullName, recipient2.fullName, recipient3.fullName);
|
||||
}
|
||||
}
|
||||
return new MessageInfo(profileImage, profileName);
|
||||
}
|
||||
}
|
@ -0,0 +1,473 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.provider.MediaStore;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.core.content.FileProvider;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.StackingBehavior;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterMessagesWebBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.readableFileSize;
|
||||
|
||||
public class RegisterMessagesWebFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "RegisterMessagesWeb";
|
||||
private App app = null;
|
||||
private Activity activity = null;
|
||||
private FragmentRegisterMessagesWebBinding b = null;
|
||||
|
||||
private WebView webView;
|
||||
private ProgressBar progressBar;
|
||||
private TextView error;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = getActivity();
|
||||
if (getActivity() == null || getContext() == null)
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_messages_web, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
private boolean isStoragePermissionGranted(Activity a) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (a.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
Log.v(TAG,"Permission is granted");
|
||||
return true;
|
||||
} else {
|
||||
|
||||
Log.v(TAG,"Permission is revoked");
|
||||
ActivityCompat.requestPermissions(a, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else { //permission is automatically granted on sdk<23 upon installation
|
||||
Log.v(TAG,"Permission is granted");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileNameFromDisposition(String header)
|
||||
{
|
||||
return header.substring(header.indexOf("\"") + 1, header.lastIndexOf("\""));
|
||||
}
|
||||
|
||||
private File downloadingFile;
|
||||
|
||||
private void enqueueFile(String url, String filename, File downloadingFile, String cookieString) {
|
||||
|
||||
this.downloadingFile = downloadingFile;
|
||||
|
||||
long downloadReference;
|
||||
|
||||
DownloadManager downloadManager;
|
||||
downloadManager = (DownloadManager)app.getSystemService(DOWNLOAD_SERVICE);
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setTitle(filename);
|
||||
request.setDescription(getString(R.string.downloading));
|
||||
request.addRequestHeader("Cookie", cookieString);
|
||||
try {
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Toast.makeText(app, "Failed to get external storage files directory", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
downloadReference = downloadManager.enqueue(request);
|
||||
}
|
||||
|
||||
private static String getMimeType(String url) {
|
||||
String type = null;
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||
if (extension != null) {
|
||||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private void openFile(File url) {
|
||||
Toast.makeText(app, getString(R.string.opening_file, url.getName()), Toast.LENGTH_SHORT).show();
|
||||
try {
|
||||
Uri uri = FileProvider.getUriForFile(app, app.getApplicationContext().getPackageName() + ".provider", url);
|
||||
//Uri uri = Uri.fromFile(url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
if (url.toString().contains(".doc") || url.toString().contains(".docx")) {
|
||||
// Word document
|
||||
intent.setDataAndType(uri, "application/msword");
|
||||
} else if (url.toString().contains(".pdf")) {
|
||||
// PDF file
|
||||
intent.setDataAndType(uri, "application/pdf");
|
||||
} else if (url.toString().contains(".ppt") || url.toString().contains(".pptx")) {
|
||||
// Powerpoint file
|
||||
intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
|
||||
} else if (url.toString().contains(".xls") || url.toString().contains(".xlsx")) {
|
||||
// Excel file
|
||||
intent.setDataAndType(uri, "application/vnd.ms-excel");
|
||||
} else if (url.toString().contains(".zip") || url.toString().contains(".rar")) {
|
||||
// WAV audio file
|
||||
intent.setDataAndType(uri, "application/x-wav");
|
||||
} else if (url.toString().contains(".rtf")) {
|
||||
// RTF file
|
||||
intent.setDataAndType(uri, "application/rtf");
|
||||
} else if (url.toString().contains(".wav") || url.toString().contains(".mp3")) {
|
||||
// WAV audio file
|
||||
intent.setDataAndType(uri, "audio/x-wav");
|
||||
} else if (url.toString().contains(".gif")) {
|
||||
// GIF file
|
||||
intent.setDataAndType(uri, "image/gif");
|
||||
} else if (url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) {
|
||||
// JPG file
|
||||
intent.setDataAndType(uri, "image/jpeg");
|
||||
} else if (url.toString().contains(".txt")) {
|
||||
// Text file
|
||||
intent.setDataAndType(uri, "text/plain");
|
||||
} else if (url.toString().contains(".3gp") || url.toString().contains(".mpg") ||
|
||||
url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) {
|
||||
// Video files
|
||||
intent.setDataAndType(uri, "video/*");
|
||||
} else {
|
||||
intent.setDataAndType(uri, "*/*");
|
||||
}
|
||||
|
||||
intent.setDataAndType(uri, getMimeType(uri.toString()));
|
||||
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
app.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(app, R.string.opening_file_no_app, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFile(Activity a, String url, String filename, long contentLength, String cookieString) {
|
||||
if (!isStoragePermissionGranted(a))
|
||||
return;
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.downloading_file)
|
||||
.content(getString((R.string.download_file_question), filename, readableFileSize(contentLength)))
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive((dialog, which) -> {
|
||||
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
File existingFile = new File(downloadsDir, filename);
|
||||
if (existingFile.exists()) {
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.downloading_file)
|
||||
.content(getString(R.string.downloading_file_exists_choose, filename))
|
||||
.stackingBehavior(StackingBehavior.ADAPTIVE)
|
||||
.positiveText(R.string.downloading_file_exists_overwrite)
|
||||
.negativeText(R.string.downloading_file_exists_open)
|
||||
.neutralText(R.string.downloading_file_exists_create_new)
|
||||
.onPositive(((dialog1, which1) -> {
|
||||
if (!existingFile.delete())
|
||||
{
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.downloading_file)
|
||||
.content(R.string.downloading_file_cannot_remove)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.onPositive(((dialog2, which2) -> enqueueFile(url, filename, existingFile, cookieString)))
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
enqueueFile(url, filename, existingFile, cookieString);
|
||||
}))
|
||||
.onNegative(((dialog1, which1) -> openFile(existingFile)))
|
||||
.onNeutral((dialog1, which1) -> enqueueFile(url, filename, existingFile, cookieString))
|
||||
.show();
|
||||
|
||||
return;
|
||||
}
|
||||
enqueueFile(url, filename, existingFile, cookieString);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private String photoPath;
|
||||
private ValueCallback<Uri> mUM;
|
||||
private ValueCallback<Uri[]> fileCallback;
|
||||
private final static int REQUEST_FILE_CHOOSER = 1;
|
||||
private boolean justLoaded = false;
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if(Build.VERSION.SDK_INT >= 21){
|
||||
Uri[] results = null;
|
||||
//Check if response is positive
|
||||
if(resultCode == RESULT_OK){
|
||||
if(requestCode == REQUEST_FILE_CHOOSER){
|
||||
if(null == fileCallback){
|
||||
return;
|
||||
}
|
||||
if(data == null){
|
||||
//Capture Photo if no image available
|
||||
if (photoPath != null) {
|
||||
results = new Uri[]{Uri.parse(photoPath)};
|
||||
}
|
||||
}else{
|
||||
String dataString = data.getDataString();
|
||||
if(dataString != null){
|
||||
results = new Uri[]{Uri.parse(dataString)};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fileCallback.onReceiveValue(results);
|
||||
fileCallback = null;
|
||||
} else {
|
||||
if (requestCode == REQUEST_FILE_CHOOSER) {
|
||||
if(null == mUM) return;
|
||||
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
|
||||
mUM.onReceiveValue(result);
|
||||
mUM = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File createImageFile() throws IOException{
|
||||
@SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
String imageFileName = "img_"+timeStamp+"_";
|
||||
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
||||
return File.createTempFile(imageFileName,".jpg",storageDir);
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
webView = b.messagesWebView;
|
||||
progressBar = b.messagesWebProgressBar;
|
||||
error = b.messagesWebError;
|
||||
|
||||
justLoaded = true;
|
||||
|
||||
new Handler().postDelayed(() -> activity.runOnUiThread(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
BroadcastReceiver onComplete = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (downloadingFile != null) {
|
||||
openFile(downloadingFile);
|
||||
downloadingFile = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
activity.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
|
||||
app.apiEdziennik.initMessagesWebView(webView, app, /*app.profile.messagesWebFullVersion*/false, false);
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
webView.getSettings().setAllowFileAccess(true);
|
||||
webView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
|
||||
String filename = getFileNameFromDisposition(contentDisposition);
|
||||
try {
|
||||
URL urlObj = new URL(url);
|
||||
Log.d(TAG, "Host "+urlObj.getProtocol()+"://"+urlObj.getHost());
|
||||
Log.d(TAG, "Cookies "+CookieManager.getInstance().getCookie(urlObj.getProtocol()+"://"+urlObj.getHost()));
|
||||
|
||||
downloadFile(getActivity(), url, filename, contentLength, CookieManager.getInstance().getCookie(urlObj.getProtocol()+"://"+urlObj.getHost()));
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Anim.fadeOut(progressBar, 400, null);
|
||||
});
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
boolean loadingFinished = true;
|
||||
boolean redirect = false;
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String request) {
|
||||
if (!loadingFinished) {
|
||||
redirect = true;
|
||||
}
|
||||
|
||||
loadingFinished = false;
|
||||
webView.loadUrl(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
RegisterMessagesWebFragment.this.error.setVisibility(View.GONE);
|
||||
loadingFinished = false;
|
||||
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
|
||||
if (progressBar.getVisibility() != View.VISIBLE)
|
||||
Anim.fadeIn(progressBar, 400, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
if (!redirect) {
|
||||
loadingFinished = true;
|
||||
}
|
||||
|
||||
if (loadingFinished && !redirect) {
|
||||
//HIDE LOADING IT HAS FINISHED
|
||||
//String cookies = CookieManager.getInstance().getCookie(url);
|
||||
//Log.d(TAG, "All the cookies in a string:" + cookies);
|
||||
Anim.fadeOut(progressBar, 400, null);
|
||||
/*if (app.profile.messagesWebFullVersion && justLoaded && app.profile.loginType == Register.LOGIN_TYPE_MOBIDZIENNIK) {
|
||||
if (!webView.getUrl().contains("wiadomosci")) {
|
||||
// redirect to messages view
|
||||
webView.loadUrl("https://" + app.getLoginData("serverName", "") + ".mobidziennik.pl/mobile/wiadomosci");
|
||||
}
|
||||
justLoaded = false;
|
||||
}*/
|
||||
} else {
|
||||
redirect = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
RegisterMessagesWebFragment.this.error.setVisibility(View.VISIBLE);
|
||||
RegisterMessagesWebFragment.this.error.setText(getString(R.string.error_occured_format, error.toString()));
|
||||
super.onReceivedError(view, request, error);
|
||||
}
|
||||
});
|
||||
|
||||
if(Build.VERSION.SDK_INT >= 21) {
|
||||
webView.getSettings().setMixedContentMode(0);
|
||||
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
} else if(Build.VERSION.SDK_INT >= 19) {
|
||||
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
} else {
|
||||
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
|
||||
webView.setWebChromeClient(new WebChromeClient(){
|
||||
//For Android 5.0+
|
||||
public boolean onShowFileChooser(
|
||||
WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
WebChromeClient.FileChooserParams fileChooserParams){
|
||||
if(fileCallback != null){
|
||||
fileCallback.onReceiveValue(null);
|
||||
}
|
||||
fileCallback = filePathCallback;
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if(takePictureIntent.resolveActivity(app.getPackageManager()) != null){
|
||||
File photoFile = null;
|
||||
try{
|
||||
photoFile = createImageFile();
|
||||
takePictureIntent.putExtra("PhotoPath", photoPath);
|
||||
}catch(IOException ex){
|
||||
Log.e(TAG, "Image file creation failed", ex);
|
||||
}
|
||||
if(photoFile != null){
|
||||
photoPath = "file:" + photoFile.getAbsolutePath();
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
|
||||
}else{
|
||||
takePictureIntent = null;
|
||||
}
|
||||
}
|
||||
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
contentSelectionIntent.setType("*/*");
|
||||
Intent[] intentArray;
|
||||
if(takePictureIntent != null){
|
||||
intentArray = new Intent[]{takePictureIntent};
|
||||
}else{
|
||||
intentArray = new Intent[0];
|
||||
}
|
||||
|
||||
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_TITLE, R.string.choose_file);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
||||
startActivityForResult(chooserIntent, REQUEST_FILE_CHOOSER);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}), 200);
|
||||
}
|
||||
|
||||
/*public void loadVersion(boolean fullVersion) {
|
||||
if (app.profile.messagesWebFullVersion != fullVersion) {
|
||||
app.profile.messagesWebFullVersion = fullVersion;
|
||||
app.profile.savePending = true;
|
||||
justLoaded = true;
|
||||
app.apiEdziennik.initMessagesWebView(webView, app, fullVersion, true);
|
||||
}
|
||||
}*/
|
||||
|
||||
public void performReload() {
|
||||
webView.reload();
|
||||
}
|
||||
|
||||
public boolean processBackKey()
|
||||
{
|
||||
if (webView.canGoBack())
|
||||
{
|
||||
webView.goBack();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.transition.TransitionValues;
|
||||
import androidx.transition.Visibility;
|
||||
|
||||
public class SlideExplode extends Visibility {
|
||||
private static final String KEY_SCREEN_BOUNDS = "screenBounds";
|
||||
|
||||
private int[] mTempLoc = new int[2];
|
||||
|
||||
private void captureValues(TransitionValues transitionValues) {
|
||||
View view = transitionValues.view;
|
||||
view.getLocationOnScreen(mTempLoc);
|
||||
int left = mTempLoc[0];
|
||||
int top = mTempLoc[1];
|
||||
int right = left + view.getWidth();
|
||||
int bottom = top + view.getHeight();
|
||||
transitionValues.values.put(KEY_SCREEN_BOUNDS, new Rect(left, top, right, bottom));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void captureStartValues(@NonNull TransitionValues transitionValues) {
|
||||
super.captureStartValues(transitionValues);
|
||||
captureValues(transitionValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void captureEndValues(@NonNull TransitionValues transitionValues) {
|
||||
super.captureEndValues(transitionValues);
|
||||
captureValues(transitionValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
|
||||
if (endValues == null)
|
||||
return null;
|
||||
|
||||
Rect bounds = (Rect) endValues.values.get(KEY_SCREEN_BOUNDS);
|
||||
float endY = view.getTranslationY();
|
||||
float startY = endY + calculateDistance(sceneRoot, bounds);
|
||||
return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
|
||||
if (startValues == null)
|
||||
return null;
|
||||
|
||||
Rect bounds = (Rect) startValues.values.get(KEY_SCREEN_BOUNDS);
|
||||
float startY = view.getTranslationY();
|
||||
float endY = startY + calculateDistance(sceneRoot, bounds);
|
||||
return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
|
||||
}
|
||||
|
||||
private int calculateDistance(View sceneRoot, Rect viewBounds) {
|
||||
sceneRoot.getLocationOnScreen(mTempLoc);
|
||||
int sceneRootY = mTempLoc[1];
|
||||
if (getEpicenter() == null) {
|
||||
return -sceneRoot.getHeight();
|
||||
}
|
||||
else if (viewBounds.top <= getEpicenter().top) {
|
||||
return sceneRootY - getEpicenter().top;
|
||||
}
|
||||
else {
|
||||
return sceneRootY + sceneRoot.getHeight() - getEpicenter().bottom;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.animation.TimeInterpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.transition.TransitionSet;
|
||||
|
||||
public class Transitions extends TransitionSet {
|
||||
@NonNull
|
||||
@Override
|
||||
public TransitionSet setInterpolator(@Nullable TimeInterpolator interpolator) {
|
||||
for (int i = 0; i < getTransitionCount(); i++) {
|
||||
getTransitionAt(i).setInterpolator(interpolator);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notices
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.os.AsyncTask
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.utils.colorRes
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.datamodels.Notice
|
||||
import pl.szczodrzynski.edziennik.datamodels.NoticeFull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.bs
|
||||
|
||||
class NoticesAdapter//getting the context and product list with constructor
|
||||
(private val context: Context, var noticeList: List<NoticeFull>) : RecyclerView.Adapter<NoticesAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
//inflating and returning our view holder
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(R.layout.row_notices_item, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val app = context.applicationContext as App
|
||||
|
||||
val notice = noticeList[position]
|
||||
|
||||
if (app.profile.loginStoreType == LOGIN_TYPE_MOBIDZIENNIK) {
|
||||
holder.noticesItemReason.text = bs(null, notice.category, "\n") + notice.text
|
||||
holder.noticesItemTeacherName.text = app.getString(R.string.notices_points_format, notice.teacherFullName, if (notice.points > 0) "+" + notice.points else notice.points)
|
||||
} else {
|
||||
holder.noticesItemReason.text = notice.text
|
||||
holder.noticesItemTeacherName.text = notice.teacherFullName
|
||||
}
|
||||
holder.noticesItemAddedDate.text = Date.fromMillis(notice.addedDate).formattedString
|
||||
|
||||
if (notice.type == Notice.TYPE_POSITIVE) {
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle)
|
||||
.colorRes(R.color.md_green_600)
|
||||
.sizeDp(36))
|
||||
} else if (notice.type == Notice.TYPE_NEGATIVE) {
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram)
|
||||
.colorRes(R.color.md_red_600)
|
||||
.sizeDp(36))
|
||||
} else {
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_message_outline)
|
||||
.colorRes(R.color.md_blue_500)
|
||||
.sizeDp(36))
|
||||
}
|
||||
|
||||
if (!notice.seen) {
|
||||
holder.noticesItemReason.background = context.resources.getDrawable(R.drawable.bg_rounded_8dp)
|
||||
when {
|
||||
notice.type == Notice.TYPE_POSITIVE -> holder.noticesItemReason.background.colorFilter = PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)
|
||||
notice.type == Notice.TYPE_NEGATIVE -> holder.noticesItemReason.background.colorFilter = PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)
|
||||
else -> holder.noticesItemReason.background.colorFilter = PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
notice.seen = true
|
||||
AsyncTask.execute { app.db.metadataDao().setSeen(App.profileId, notice, true) }
|
||||
} else {
|
||||
holder.noticesItemReason.background = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return noticeList.size
|
||||
}
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var noticesItemCard: CardView = itemView.findViewById(R.id.noticesItemCard)
|
||||
var noticesItemType: ImageView = itemView.findViewById(R.id.noticesItemType)
|
||||
var noticesItemReason: TextView = itemView.findViewById(R.id.noticesItemReason)
|
||||
var noticesItemTeacherName: TextView = itemView.findViewById(R.id.noticesItemTeacherName)
|
||||
var noticesItemAddedDate: TextView = itemView.findViewById(R.id.noticesItemAddedDate)
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notices;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterNoticesBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Notice;
|
||||
import pl.szczodrzynski.edziennik.datamodels.NoticeFull;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Metadata.TYPE_NOTICE;
|
||||
|
||||
public class RegisterNoticesFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterNoticesBinding b = null;
|
||||
|
||||
private int displayMode = MODE_YEAR;
|
||||
private static final int MODE_YEAR = 0;
|
||||
private static final int MODE_SEMESTER_1 = 1;
|
||||
private static final int MODE_SEMESTER_2 = 2;
|
||||
|
||||
private List<NoticeFull> noticeList = 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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_notices, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_NOTICE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_NOTICES, b.refreshLayout);
|
||||
});*/
|
||||
|
||||
b.noticesSummaryTitle.setOnClickListener((v -> {
|
||||
PopupMenu popupMenu = new PopupMenu(activity, b.noticesSummaryTitle, Gravity.END);
|
||||
popupMenu.getMenu().add(0, 0, 0, R.string.summary_mode_year);
|
||||
popupMenu.getMenu().add(0, 1, 1, R.string.summary_mode_semester_1);
|
||||
popupMenu.getMenu().add(0, 2, 2, R.string.summary_mode_semester_2);
|
||||
popupMenu.setOnMenuItemClickListener((item -> {
|
||||
displayMode = item.getItemId();
|
||||
updateList();
|
||||
return true;
|
||||
}));
|
||||
popupMenu.show();
|
||||
}));
|
||||
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
|
||||
b.noticesView.setHasFixedSize(true);
|
||||
b.noticesView.setLayoutManager(linearLayoutManager);
|
||||
|
||||
app.db.noticeDao().getAll(App.profileId).observe(this, notices -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (notices == null) {
|
||||
b.noticesView.setVisibility(View.GONE);
|
||||
b.noticesNoData.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
noticeList = notices;
|
||||
|
||||
updateList();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
int praisesCount = 0;
|
||||
int warningsCount = 0;
|
||||
int otherCount = 0;
|
||||
|
||||
List<NoticeFull> filteredList = new ArrayList<>();
|
||||
for (NoticeFull notice: noticeList) {
|
||||
if (displayMode != MODE_YEAR && notice.semester != displayMode)
|
||||
continue;
|
||||
filteredList.add(notice);
|
||||
switch (notice.type) {
|
||||
case Notice.TYPE_POSITIVE:
|
||||
praisesCount++;
|
||||
break;
|
||||
case Notice.TYPE_NEGATIVE:
|
||||
warningsCount++;
|
||||
break;
|
||||
case Notice.TYPE_NEUTRAL:
|
||||
otherCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filteredList.size() > 0) {
|
||||
NoticesAdapter adapter;
|
||||
b.noticesView.setVisibility(View.VISIBLE);
|
||||
b.noticesNoData.setVisibility(View.GONE);
|
||||
if ((adapter = (NoticesAdapter) b.noticesView.getAdapter()) != null) {
|
||||
adapter.setNoticeList(filteredList);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
else {
|
||||
adapter = new NoticesAdapter(getContext(), filteredList);
|
||||
b.noticesView.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
else {
|
||||
b.noticesView.setVisibility(View.GONE);
|
||||
b.noticesNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (displayMode == MODE_YEAR) {
|
||||
b.noticesSummaryTitle.setText(getString(R.string.notices_summary_title_year));
|
||||
}
|
||||
else {
|
||||
b.noticesSummaryTitle.setText(getString(R.string.notices_summary_title_semester_format, displayMode));
|
||||
}
|
||||
b.noticesPraisesCount.setText(String.format(Locale.getDefault(), "%d", praisesCount));
|
||||
b.noticesWarningsCount.setText(String.format(Locale.getDefault(), "%d", warningsCount));
|
||||
b.noticesOtherCount.setText(String.format(Locale.getDefault(), "%d", otherCount));
|
||||
if (warningsCount >= 3) {
|
||||
b.noticesWarningsCount.setTextColor(Color.RED);
|
||||
}
|
||||
else {
|
||||
b.noticesWarningsCount.setTextColor(Themes.INSTANCE.getPrimaryTextColor(activity));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdapter.ViewHolder> {
|
||||
private static final String TAG = "NotificationsAdapter";
|
||||
private Context context;
|
||||
private List<Notification> notificationList;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public NotificationsAdapter(Context mCtx, List<Notification> notificationList) {
|
||||
this.context = mCtx;
|
||||
this.notificationList = notificationList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.row_notifications_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
|
||||
Notification notification = notificationList.get(position);
|
||||
|
||||
holder.notificationsItemDate.setText(Date.fromMillis(notification.addedDate).getFormattedString());
|
||||
holder.notificationsItemText.setText(notification.text);
|
||||
holder.notificationsItemTitle.setText(notification.title);
|
||||
holder.notificationsItemType.setText(Notification.stringType(context, notification.type));
|
||||
|
||||
holder.notificationsItemCard.setOnClickListener((v -> {
|
||||
Intent intent = new Intent("android.intent.action.MAIN");
|
||||
notification.fillIntent(intent);
|
||||
|
||||
d(TAG, "notification with item "+notification.redirectFragmentId+" extras "+(intent.getExtras() == null ? "null" : intent.getExtras().toString()));
|
||||
|
||||
//Log.d(TAG, "Got date "+intent.getLongExtra("timetableDate", 0));
|
||||
|
||||
if (notification.profileId != -1 && notification.profileId != app.profile.getId() && context instanceof Activity) {
|
||||
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
app.sendBroadcast(intent);
|
||||
}));
|
||||
|
||||
if (!notification.seen) {
|
||||
holder.notificationsItemText.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
|
||||
holder.notificationsItemText.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
else {
|
||||
holder.notificationsItemText.setBackground(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return notificationList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
CardView notificationsItemCard;
|
||||
TextView notificationsItemDate;
|
||||
TextView notificationsItemText;
|
||||
TextView notificationsItemTitle;
|
||||
TextView notificationsItemType;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
notificationsItemCard = itemView.findViewById(R.id.notificationsItemCard);
|
||||
notificationsItemDate = itemView.findViewById(R.id.notificationsItemDate);
|
||||
notificationsItemText = itemView.findViewById(R.id.notificationsItemText);
|
||||
notificationsItemTitle = itemView.findViewById(R.id.notificationsItemTitle);
|
||||
notificationsItemType = itemView.findViewById(R.id.notificationsItemType);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterNotificationsBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
public class RegisterNotificationsFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private Activity activity = null;
|
||||
private FragmentRegisterNotificationsBinding b = null;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = getActivity();
|
||||
if (getActivity() == null || getContext() == null)
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_notifications, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
RecyclerView recyclerView = b.notificationsView;
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
if (app.appConfig.notifications.size() > 0) {
|
||||
NotificationsAdapter adapter = new NotificationsAdapter(getContext(), app.appConfig.notifications);
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
//linearLayoutManager.setReverseLayout(true);
|
||||
//linearLayoutManager.setStackFromEnd(true);
|
||||
recyclerView.setLayoutManager(linearLayoutManager);
|
||||
b.notificationsNoData.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
b.notificationsNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentProfileManagerBinding
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class ProfileManagerFragment : Fragment() {
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentProfileManagerBinding
|
||||
/*
|
||||
private val navController: NavController by lazy { Navigation.findNavController(b.root) }
|
||||
*/
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
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 = FragmentProfileManagerBinding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
||||
import com.danielstone.materialaboutlibrary.ConvenienceBuilder
|
||||
import com.danielstone.materialaboutlibrary.MaterialAboutActivity
|
||||
import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
|
||||
import com.danielstone.materialaboutlibrary.model.MaterialAboutList
|
||||
import com.danielstone.materialaboutlibrary.util.OpenSourceLicense
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
|
||||
class SettingsLicenseActivity : MaterialAboutActivity() {
|
||||
|
||||
var foregroundColor: Int = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val app = application as App
|
||||
setTheme(Themes.appTheme)
|
||||
foregroundColor = Themes.getPrimaryTextColor(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun createLicenseCard(
|
||||
context: Context,
|
||||
libraryTitle: CharSequence,
|
||||
copyrightYear: CharSequence,
|
||||
copyrightName: CharSequence,
|
||||
license: OpenSourceLicense,
|
||||
libraryUrl: String): MaterialAboutCard {
|
||||
val licenseItem = MaterialAboutActionItem.Builder()
|
||||
.icon(IconicsDrawable(this)
|
||||
.icon(CommunityMaterial.Icon.cmd_book)
|
||||
.colorInt(foregroundColor)
|
||||
.sizeDp(18))
|
||||
.setIconGravity(MaterialAboutActionItem.GRAVITY_TOP)
|
||||
.text(libraryTitle)
|
||||
.subText(String.format(getString(license.resourceId), copyrightYear, copyrightName))
|
||||
.setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(context, Uri.parse(libraryUrl)))
|
||||
.build()
|
||||
|
||||
return MaterialAboutCard.Builder().addItem(licenseItem).build()
|
||||
}
|
||||
|
||||
override fun getMaterialAboutList(context: Context): MaterialAboutList {
|
||||
|
||||
return MaterialAboutList(
|
||||
createLicenseCard(this,
|
||||
"OkHttp",
|
||||
"",
|
||||
"square",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/square/okhttp/"),
|
||||
createLicenseCard(this,
|
||||
"MHttp",
|
||||
"2018",
|
||||
"Mot.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/motcwang/MHttp/"),
|
||||
createLicenseCard(this,
|
||||
"AgendaCalendarView",
|
||||
"2015",
|
||||
"Thibault Guégan",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Tibolte/AgendaCalendarView/"),
|
||||
createLicenseCard(this,
|
||||
"Material Calendar View",
|
||||
"2017",
|
||||
"Applandeo sp. z o.o.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Applandeo/Material-Calendar-View/"),
|
||||
createLicenseCard(this,
|
||||
"Android-Job",
|
||||
"2007-2017",
|
||||
"Evernote Corporation",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/evernote/android-job/"),
|
||||
createLicenseCard(this,
|
||||
"Custom Activity On Crash",
|
||||
"",
|
||||
"Eduard Ereza MartĂnez (Ereza)",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/Ereza/CustomActivityOnCrash/"),
|
||||
createLicenseCard(this,
|
||||
"Android-Iconics",
|
||||
"2018",
|
||||
"Mike Penz",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/mikepenz/Android-Iconics/"),
|
||||
createLicenseCard(this,
|
||||
"MaterialDrawer",
|
||||
"2016",
|
||||
"Mike Penz",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/mikepenz/MaterialDrawer/"),
|
||||
createLicenseCard(this,
|
||||
"Material Dialogs",
|
||||
"2014-2016",
|
||||
"Aidan Michael Follestad",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/afollestad/material-dialogs/"),
|
||||
createLicenseCard(this,
|
||||
"MaterialDateTimePicker",
|
||||
"2014",
|
||||
"Wouter Dullaert",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/wdullaer/MaterialDateTimePicker/"),
|
||||
createLicenseCard(this,
|
||||
"ColorPicker",
|
||||
"2016",
|
||||
"Jared Rummler, 2015 Daniel Nilsson",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/jaredrummler/ColorPicker/"),
|
||||
createLicenseCard(this,
|
||||
"material-about-library",
|
||||
"2016-2018",
|
||||
"Daniel Stone",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/daniel-stoneuk/material-about-library/"),
|
||||
createLicenseCard(this,
|
||||
"material-intro",
|
||||
"2017",
|
||||
"Jan Heinrich Reimer",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/heinrichreimer/material-intro/"),
|
||||
createLicenseCard(this,
|
||||
"JsonViewer",
|
||||
"2017",
|
||||
"smuyyh",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/smuyyh/JsonViewer/"),
|
||||
createLicenseCard(this,
|
||||
"ShortcutBadger",
|
||||
"2014",
|
||||
"Leo Lin",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/leolin310148/ShortcutBadger/"),
|
||||
createLicenseCard(this,
|
||||
"Android Image Cropper",
|
||||
"2016",
|
||||
"Arthur Teplitzki, 2013 Edmodo, Inc.",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/ArthurHub/Android-Image-Cropper/"),
|
||||
createLicenseCard(this,
|
||||
"Material Tap Target Prompt",
|
||||
"2016-2018",
|
||||
"Samuel Wall",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/sjwall/MaterialTapTargetPrompt/"),
|
||||
createLicenseCard(this,
|
||||
"Android Swipe Layout",
|
||||
"2014",
|
||||
"代码家 (daimajia)",
|
||||
OpenSourceLicense.MIT,
|
||||
"https://github.com/daimajia/AndroidSwipeLayout/"),
|
||||
createLicenseCard(this,
|
||||
"barcodescanner (ZXing)",
|
||||
"2014",
|
||||
"Dushyanth Maguluru",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/dm77/barcodescanner/"),
|
||||
createLicenseCard(this,
|
||||
"CircularProgressIndicator",
|
||||
"2018",
|
||||
"Anton Kozyriatskyi",
|
||||
OpenSourceLicense.APACHE_2,
|
||||
"https://github.com/antonKozyriatskyi/CircularProgressIndicator/")
|
||||
|
||||
|
||||
/*createLicenseCard(this,
|
||||
"NoNonsense-FilePicker",
|
||||
"",
|
||||
"Jonas Kalderstam (spacecowboy)",
|
||||
OpenSourceLicense.GNU_GPL_3,
|
||||
"https://github.com/spacecowboy/NoNonsense-FilePicker/")*/
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
override fun getActivityTitle(): CharSequence? {
|
||||
return getString(R.string.settings_about_licenses_text)
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,89 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.timetable;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterTimetableDayBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
public class RegisterTimetableDayFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterTimetableDayBinding b = null;
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
@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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_timetable_day, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
/*b.getRoot().setOnTouchListener((v, event) -> {
|
||||
d("TimetableDay", "event "+event);
|
||||
event.setSource(0x10000000); // set a unique source
|
||||
activity.swipeRefreshLayout.onTouchEvent(event);
|
||||
return true;
|
||||
});*/
|
||||
//b.refreshLayout.setNestedScrollingEnabled(true);
|
||||
/*b.refreshLayout.setOnRefreshListener(() -> {
|
||||
activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_TIMETABLE, b.refreshLayout);
|
||||
});*/
|
||||
|
||||
assert getArguments() != null;
|
||||
Date date = new Date().parseFromYmd(Long.toString(getArguments().getLong("date", 20181009)));
|
||||
|
||||
recyclerView = b.timetableView;
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
app.db.lessonDao().getAllByDate(App.profileId, date, Time.getNow()).observe(this, lessons -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (lessons != null && lessons.size() > 0) {
|
||||
app.db.eventDao().getAllByDate(App.profileId, date).observe(this, events -> {
|
||||
TimetableAdapter adapter = new TimetableAdapter(getContext(), date, lessons, events == null ? new ArrayList<>() : events);
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
b.timetableNoData.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
else {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
b.timetableNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,628 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.timetable;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.cardview.widget.CardView;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentRegisterTimetableBinding;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LessonChange.TYPE_CANCELLED;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.LessonChange.TYPE_CHANGE;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Metadata.TYPE_LESSON_CHANGE;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class RegisterTimetableFragment extends Fragment {
|
||||
private static final String TAG = "RegisterTimetable";
|
||||
|
||||
private App app = null;
|
||||
private MainActivity activity = null;
|
||||
private FragmentRegisterTimetableBinding b = null;
|
||||
|
||||
private ViewPager viewPager;
|
||||
private static int pageSelection = -1;
|
||||
private static Date displayingDate;
|
||||
|
||||
@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.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_register_timetable, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
.withDescription(R.string.menu_add_event_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.main_menu_add)
|
||||
.items(R.array.main_menu_add_options)
|
||||
.itemsCallback((dialog, itemView, position, text) -> {
|
||||
switch (position) {
|
||||
case 0:
|
||||
new EventManualDialog(activity).show(app, null, displayingDate, null, EventManualDialog.DIALOG_EVENT);
|
||||
break;
|
||||
case 1:
|
||||
new EventManualDialog(activity).show(app, null, displayingDate, null, EventManualDialog.DIALOG_HOMEWORK);
|
||||
break;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_generate_block_timetable)
|
||||
.withDescription(R.string.menu_generate_block_timetable_desc)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_table_large)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
generateBlockTimetable();
|
||||
}),
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_LESSON_CHANGE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
activity.gainAttention();
|
||||
|
||||
// Setting ViewPager for each Tabs
|
||||
viewPager = b.viewpager;
|
||||
Adapter adapter = new Adapter(getChildFragmentManager());
|
||||
|
||||
Date today = Date.getToday();
|
||||
|
||||
Date date = Date.getToday();
|
||||
int weekBeginning = app.appConfig.timetableDisplayDaysBackward - date.getWeekDay();
|
||||
int weekEnd = weekBeginning + 6;
|
||||
date.stepForward(0, 0, 0 - (app.appConfig.timetableDisplayDaysBackward));
|
||||
for (int i = 0; i < app.appConfig.timetableDisplayDaysForward + app.appConfig.timetableDisplayDaysBackward + 1; i++) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("date", date.getValue());
|
||||
RegisterTimetableDayFragment registerTimetableDayFragment = new RegisterTimetableDayFragment();
|
||||
registerTimetableDayFragment.setArguments(args);
|
||||
StringBuilder pageTitle = new StringBuilder(Week.getFullDayName(date.getWeekDay()));
|
||||
if (i > weekEnd || i < weekBeginning) {
|
||||
pageTitle.append(", ").append(date.getStringDm());
|
||||
}
|
||||
adapter.addFragment(registerTimetableDayFragment, pageTitle.toString());
|
||||
date.stepForward(0, 0, 1);
|
||||
}
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
|
||||
if (getArguments() != null && getArguments().getLong("timetableDate", 0) != 0) {
|
||||
Date gotDate = new Date().parseFromYmd(Long.toString(getArguments().getLong("timetableDate", 0))); // OVERRIDE HERE
|
||||
// DAMNIT
|
||||
// THE TIMETABLE WAS DOING LOTS OF WEIRD THINGS (incorrect default days, sometimes scrolling to the beginning)
|
||||
// BECAUSE THESE TWO LINES WERE SWAPPED.
|
||||
//pageSelection += Date.diffDays(gotDate, displayingDate);
|
||||
|
||||
Log.d(TAG, "Got date "+getArguments().getLong("timetableDate", 0));
|
||||
|
||||
pageSelection = app.appConfig.timetableDisplayDaysBackward + Date.diffDays(gotDate, today);
|
||||
displayingDate = gotDate;
|
||||
}
|
||||
else if (pageSelection == -1) {
|
||||
AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
List<LessonFull> lessons = app.db.lessonDao().getAllWeekNow(App.profileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today);
|
||||
displayingDate = HomeFragment.findDateWithLessons(App.profileId, lessons);
|
||||
pageSelection = app.appConfig.timetableDisplayDaysBackward + Date.diffDays(displayingDate, today); // DEFAULT HERE
|
||||
|
||||
activity.runOnUiThread(() -> {
|
||||
viewPager.setCurrentItem(pageSelection, false);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
viewPager.setCurrentItem(pageSelection, false);
|
||||
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
|
||||
@Override public void onPageScrollStateChanged(int state) { }
|
||||
@Override public void onPageSelected(int position) {
|
||||
pageSelection = position;
|
||||
Fragment fragment = adapter.getItem(position);
|
||||
assert fragment.getArguments() != null;
|
||||
displayingDate = new Date().parseFromYmd(Long.toString(fragment.getArguments().getLong("date", 20181009)));
|
||||
/*
|
||||
Fragment fragment = adapter.getItem(position);
|
||||
int scrolledDate = fragment.getArguments().getInt("date", 0);
|
||||
//Toast.makeText(app, "Date: "+scrolledDate, Toast.LENGTH_SHORT).show();
|
||||
Collection<Integer> removeDates = new ArrayList<>();
|
||||
for (Integer lessonChangeDate: unreadLessonChangesDates) {
|
||||
if (lessonChangeDate.equals(scrolledDate)) {
|
||||
for (RegisterLessonChange lessonChange: app.profile.timetable.lessonChanges) {
|
||||
if (lessonChange.lessonDate.getValue() == lessonChangeDate) {
|
||||
lessonChange.notified = true;
|
||||
}
|
||||
}
|
||||
removeDates.add(lessonChangeDate);
|
||||
}
|
||||
}
|
||||
unreadLessonChangesDates.removeAll(removeDates);
|
||||
|
||||
if (app.profile.unreadLessonChanges != unreadLessonChangesDates.size()) {
|
||||
app.profile.unreadLessonChanges = unreadLessonChangesDates.size();
|
||||
app.profile.savePending = true;
|
||||
Intent i = new Intent("android.intent.action.MAIN").putExtra(MainActivity.ACTION_UPDATE_BADGES, "yes, sure");
|
||||
getContext().sendBroadcast(i);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
});
|
||||
|
||||
// Set Tabs inside Toolbar
|
||||
TabLayout tabs = view.findViewById(R.id.result_tabs);
|
||||
tabs.setupWithViewPager(viewPager);
|
||||
|
||||
/*if (!app.appConfig.tapTargetSetAsRead) {
|
||||
new MaterialTapTargetPrompt.Builder(activity)
|
||||
.setTarget(activity.findViewById(R.id.action_mark_as_read))
|
||||
.setPrimaryText(R.string.tap_target_set_as_read_title)
|
||||
.setSecondaryText(R.string.tap_target_set_as_read_text)
|
||||
.setFocalColour(Color.TRANSPARENT)
|
||||
.setPromptStateChangeListener((prompt, state) -> {
|
||||
if (state == MaterialTapTargetPrompt.STATE_FOCAL_PRESSED) {
|
||||
// User has pressed the prompt target
|
||||
}
|
||||
})
|
||||
.show();
|
||||
app.appConfig.tapTargetSetAsRead = true;
|
||||
app.appConfig.savePending = true;
|
||||
}*/
|
||||
}
|
||||
|
||||
public static Bitmap getBitmapFromView(View view) {
|
||||
//Define a bitmap with the same size as the view
|
||||
Bitmap returnedBitmap = Bitmap.createBitmap(view.getLayoutParams().width, view.getLayoutParams().height, Bitmap.Config.ARGB_8888);
|
||||
//Bind a canvas to it
|
||||
Canvas canvas = new Canvas(returnedBitmap);
|
||||
//Get the view's background
|
||||
Drawable bgDrawable = view.getBackground();
|
||||
if (bgDrawable!=null)
|
||||
//has background drawable, then draw it on the canvas
|
||||
bgDrawable.draw(canvas);
|
||||
else
|
||||
//does not have background drawable, then draw white background on the canvas
|
||||
canvas.drawColor(Color.TRANSPARENT);
|
||||
// draw the view on the canvas
|
||||
view.draw(canvas);
|
||||
//return the bitmap
|
||||
return returnedBitmap;
|
||||
}
|
||||
|
||||
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
|
||||
int width = bm.getWidth();
|
||||
int height = bm.getHeight();
|
||||
float scaleWidth = ((float) newWidth) / width;
|
||||
float scaleHeight = ((float) newHeight) / height;
|
||||
// CREATE A MATRIX FOR THE MANIPULATION
|
||||
Matrix matrix = new Matrix();
|
||||
// RESIZE THE BIT MAP
|
||||
matrix.postScale(scaleWidth, scaleHeight);
|
||||
|
||||
// "RECREATE" THE NEW BITMAP
|
||||
Bitmap resizedBitmap = Bitmap.createBitmap(
|
||||
bm, 0, 0, width, height, matrix, true);
|
||||
bm.recycle();
|
||||
return resizedBitmap;
|
||||
}
|
||||
|
||||
public void generateBlockTimetable() {
|
||||
if (getActivity() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Date weekCurrentStart = Week.getWeekStart();
|
||||
Date weekCurrentEnd = Week.getWeekEnd();
|
||||
Date weekNextStart = weekCurrentEnd.clone().stepForward(0, 0, 1);
|
||||
Date weekNextEnd = weekNextStart.clone().stepForward(0, 0, 6);
|
||||
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.title(R.string.timetable_generate_range)
|
||||
.items(
|
||||
getString(R.string.timetable_generate_no_changes),
|
||||
getString(R.string.timetable_generate_current_week_format, weekCurrentStart.getFormattedStringShort(), weekCurrentEnd.getFormattedStringShort()),
|
||||
getString(R.string.timetable_generate_next_week_format, weekNextStart.getFormattedStringShort(), weekNextEnd.getFormattedStringShort()),
|
||||
getString(R.string.timetable_generate_for_printout))
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.checkBoxPromptRes(R.string.timetable_generate_include_profile_name, true, null)
|
||||
.itemsCallbackSingleChoice(0, (dialog, itemView, which, text) -> {
|
||||
Toast.makeText(app, "Selected "+which, Toast.LENGTH_SHORT).show();
|
||||
AsyncTask.execute(() -> {
|
||||
switch (which) {
|
||||
case 0:
|
||||
generateBlockTimetableWithLessons(app.db.lessonDao().getAllWeekNow(App.profileId, weekCurrentStart, weekCurrentStart), false, dialog.isPromptCheckBoxChecked(), null, null, false);
|
||||
break;
|
||||
case 1:
|
||||
generateBlockTimetableWithLessons(app.db.lessonDao().getAllWeekNow(App.profileId, weekCurrentStart, weekCurrentStart), true, dialog.isPromptCheckBoxChecked(), weekCurrentStart, weekCurrentEnd, false);
|
||||
break;
|
||||
case 2:
|
||||
generateBlockTimetableWithLessons(app.db.lessonDao().getAllWeekNow(App.profileId, weekNextStart, weekNextStart), true, dialog.isPromptCheckBoxChecked(), weekNextStart, weekNextEnd, false);
|
||||
break;
|
||||
case 3:
|
||||
generateBlockTimetableWithLessons(app.db.lessonDao().getAllWeekNow(App.profileId, weekCurrentStart, weekCurrentStart), false, dialog.isPromptCheckBoxChecked(), null, null, true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (which == 0) {
|
||||
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.show();
|
||||
|
||||
}
|
||||
|
||||
private MaterialDialog progressDialog;
|
||||
|
||||
private void generateBlockTimetableWithLessons(List<LessonFull> lessonList, boolean markChanges, boolean showProfileName, Date weekStart, Date weekEnd, boolean noColors) {
|
||||
d(TAG, Arrays.toString(lessonList.toArray()));
|
||||
|
||||
activity.runOnUiThread(() -> {
|
||||
progressDialog = new MaterialDialog.Builder(activity)
|
||||
.title(R.string.timetable_generate_progress_title)
|
||||
.content(R.string.timetable_generate_progress_text)
|
||||
.progress(true, 0)
|
||||
.show();
|
||||
});
|
||||
|
||||
// block size: 190x90, so one minute is 2px
|
||||
// spacing: 15x10
|
||||
// left size: 45px
|
||||
// header size: 45px
|
||||
// overall width: 45 + n*(190+15)
|
||||
// overall height: 45 + n*(90+10)
|
||||
// footer size 30px
|
||||
|
||||
int WIDTH_CONSTANT = 70;
|
||||
int WIDTH_WEEKDAY = 285;
|
||||
int WIDTH_SPACING = 15;
|
||||
int HEIGHT_PROFILE_NAME = showProfileName ? 100 : 0;
|
||||
int HEIGHT_CONSTANT = 60;
|
||||
int HEIGHT_MINUTE = 3;
|
||||
int HEIGHT_FOOTER = 40;
|
||||
|
||||
List<List<LessonFull>> weekdays = new ArrayList<>();
|
||||
for(int i = 0; i < 7; i++) {
|
||||
weekdays.add(new ArrayList<>());
|
||||
}
|
||||
int maxWeekDay = 5;
|
||||
Time minTime = null;
|
||||
Time maxTime = null;
|
||||
|
||||
TreeMap<Integer, Integer> lessonRanges = new TreeMap<>();
|
||||
|
||||
for (LessonFull lesson: lessonList) {
|
||||
if (lesson.weekDay > maxWeekDay)
|
||||
maxWeekDay = lesson.weekDay;
|
||||
List<LessonFull> weekdayLessons = weekdays.get(lesson.weekDay);
|
||||
weekdayLessons.add(lesson);
|
||||
lessonRanges.put(lesson.startTime.getValue(), lesson.endTime.getValue());
|
||||
if (minTime == null || lesson.startTime.getValue() < minTime.getValue()) {
|
||||
minTime = lesson.startTime;
|
||||
}
|
||||
if (maxTime == null || lesson.endTime.getValue() > maxTime.getValue()) {
|
||||
maxTime = lesson.endTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (minTime != null) {
|
||||
d(TAG, "Min time "+minTime.getValue()+" max time "+maxTime.getValue());
|
||||
Time diff = Time.diff(maxTime, minTime);
|
||||
int minutes = diff.hour*60+diff.minute;
|
||||
|
||||
Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
|
||||
int imgWidth = WIDTH_CONSTANT + maxWeekDay * WIDTH_WEEKDAY + (maxWeekDay-1) * WIDTH_SPACING;
|
||||
int imgHeight = HEIGHT_PROFILE_NAME + HEIGHT_CONSTANT + minutes*HEIGHT_MINUTE + HEIGHT_FOOTER;
|
||||
Bitmap bmp = Bitmap.createBitmap(imgWidth+20, imgHeight+30, conf); // this creates a MUTABLE bitmap
|
||||
Canvas canvas = new Canvas(bmp);
|
||||
if (noColors)
|
||||
canvas.drawARGB(255, 255, 255, 255);
|
||||
else
|
||||
canvas.drawARGB(255, 225, 225, 225);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setFilterBitmap(true);
|
||||
paint.setDither(true);
|
||||
|
||||
for (LessonFull lesson: lessonList) {
|
||||
Time lessonLength = Time.diff(lesson.endTime, lesson.startTime);
|
||||
Time firstOffset = Time.diff(lesson.startTime, minTime);
|
||||
|
||||
int left = WIDTH_CONSTANT + lesson.weekDay*WIDTH_WEEKDAY + lesson.weekDay * WIDTH_SPACING;
|
||||
int top = HEIGHT_PROFILE_NAME + HEIGHT_CONSTANT + (firstOffset.hour*60+firstOffset.minute)*HEIGHT_MINUTE;
|
||||
int blockWidth = WIDTH_WEEKDAY;
|
||||
int blockHeight = (lessonLength.hour*60+lessonLength.minute)*HEIGHT_MINUTE;
|
||||
int viewWidth = Utils.dpToPx(380);
|
||||
int viewHeight = Utils.dpToPx((lessonLength.hour*60+lessonLength.minute)*4);
|
||||
|
||||
LinearLayout linearLayout;
|
||||
try {
|
||||
linearLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.row_timetable_block_item, null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
app.apiEdziennik.guiReportException(activity, 385, e);
|
||||
return;
|
||||
}
|
||||
|
||||
LinearLayout layout = linearLayout.findViewById(R.id.timetableItemLayout);
|
||||
CardView card = linearLayout.findViewById(R.id.timetableItemCard);
|
||||
TextView subjectName = linearLayout.findViewById(R.id.timetableItemSubjectName);
|
||||
TextView classroomName = linearLayout.findViewById(R.id.timetableItemClassroomName);
|
||||
TextView teacherName = linearLayout.findViewById(R.id.timetableItemTeacherName);
|
||||
TextView teamName = linearLayout.findViewById(R.id.timetableItemTeamName);
|
||||
|
||||
if (noColors) {
|
||||
card.setCardBackgroundColor(0xffffffff);
|
||||
card.setCardElevation(0.0f);
|
||||
layout.setBackgroundResource(R.drawable.bg_rounded_16dp_outline);
|
||||
subjectName.setTextColor(0xff000000);
|
||||
classroomName.setTextColor(0xffaaaaaa);
|
||||
teacherName.setTextColor(0xffaaaaaa);
|
||||
teamName.setTextColor(0xffaaaaaa);
|
||||
}
|
||||
|
||||
subjectName.setText(lesson.subjectLongName);
|
||||
classroomName.setText(bs(lesson.classroomName));
|
||||
teacherName.setText(bs(lesson.teacherFullName));
|
||||
teamName.setText(bs(lesson.teamName));
|
||||
|
||||
if (markChanges) {
|
||||
if (lesson.changeId != 0) {
|
||||
if (lesson.changeType == TYPE_CANCELLED) {
|
||||
card.setCardBackgroundColor(Color.BLACK);
|
||||
subjectName.setText(Html.fromHtml("<del>"+lesson.subjectLongName+"</del>", null, new SpannableHtmlTagHandler()));
|
||||
}
|
||||
else if (lesson.changeType == TYPE_CHANGE) {
|
||||
card.setCardBackgroundColor(0xff234158); // 0x40 x primary
|
||||
subjectName.setTypeface(null, Typeface.BOLD_ITALIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
linearLayout.setDrawingCacheEnabled(true);
|
||||
linearLayout.measure(View.MeasureSpec.makeMeasureSpec(viewWidth, View.MeasureSpec.EXACTLY),
|
||||
View.MeasureSpec.makeMeasureSpec(viewHeight, View.MeasureSpec.EXACTLY));
|
||||
linearLayout.layout(0, 0, linearLayout.getMeasuredWidth(), linearLayout.getMeasuredHeight());
|
||||
linearLayout.buildDrawingCache(true);
|
||||
|
||||
Bitmap bm = linearLayout.getDrawingCache();
|
||||
canvas.drawBitmap(bm, null, new Rect(left, top, left+blockWidth, top+blockHeight), paint);
|
||||
}
|
||||
|
||||
Paint textPaint = new Paint();
|
||||
textPaint.setARGB(255, 0, 0, 0);
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
textPaint.setTextSize(30);
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setFilterBitmap(true);
|
||||
textPaint.setDither(true);
|
||||
|
||||
for (int w = 0; w < maxWeekDay+1; w++) {
|
||||
int x = WIDTH_CONSTANT + w*WIDTH_WEEKDAY + w * WIDTH_SPACING;
|
||||
canvas.drawText(Week.getFullDayName(w), x + (WIDTH_WEEKDAY/2), HEIGHT_PROFILE_NAME + HEIGHT_CONSTANT/2+10, textPaint);
|
||||
}
|
||||
|
||||
if (showProfileName) {
|
||||
textPaint.setTextSize(50);
|
||||
if (weekStart != null && weekEnd != null) {
|
||||
canvas.drawText(app.profile.getName() + " - plan lekcji, "+weekStart.getFormattedStringShort() + " - " + weekEnd.getFormattedStringShort(), (imgWidth + 20) / 2, 80, textPaint);
|
||||
}
|
||||
else {
|
||||
canvas.drawText(app.profile.getName() + " - plan lekcji", (imgWidth + 20) / 2, 80, textPaint);
|
||||
}
|
||||
}
|
||||
|
||||
textPaint.setARGB(128, 0, 0, 0);
|
||||
textPaint.setTextAlign(Paint.Align.RIGHT);
|
||||
textPaint.setTextSize(26);
|
||||
textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC));
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setFilterBitmap(true);
|
||||
textPaint.setDither(true);
|
||||
int textPaintCenter = Math.round((textPaint.descent() + textPaint.ascent()) / 2);
|
||||
canvas.drawText("Wygenerowano w aplikacji Szkolny.eu", imgWidth - 10, imgHeight - textPaintCenter - 10, textPaint);
|
||||
|
||||
textPaint.setARGB(255, 127, 127, 127);
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
textPaint.setTextSize(16);
|
||||
textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setFilterBitmap(true);
|
||||
textPaint.setDither(true);
|
||||
textPaintCenter = Math.round((textPaint.descent() + textPaint.ascent()) / 2); // it's probably negative
|
||||
|
||||
Paint linePaint = new Paint();
|
||||
linePaint.setARGB(255, 100, 100, 100);
|
||||
linePaint.setStyle(Paint.Style.STROKE);
|
||||
linePaint.setPathEffect(new DashPathEffect(new float[]{10, 10}, 0));
|
||||
linePaint.setAntiAlias(true);
|
||||
linePaint.setFilterBitmap(true);
|
||||
linePaint.setDither(true);
|
||||
|
||||
int minTimeVal = minTime.getValue();
|
||||
int minTimeInt = (minTimeVal/10000)*60 + ((minTimeVal/100)%100);
|
||||
for (int startTime: lessonRanges.keySet()) {
|
||||
Integer endTime = lessonRanges.get(startTime);
|
||||
if (endTime == null)
|
||||
continue;
|
||||
|
||||
int hour = startTime/10000;
|
||||
int minute = (startTime/100)%100;
|
||||
int firstOffset = hour * 60 + minute - minTimeInt; // offset in minutes
|
||||
int top = HEIGHT_PROFILE_NAME + HEIGHT_CONSTANT + firstOffset*HEIGHT_MINUTE;
|
||||
String text = hour+":"+(minute < 10 ? "0"+minute : minute);
|
||||
canvas.drawText(text, WIDTH_CONSTANT/2, top-textPaintCenter, textPaint);
|
||||
canvas.drawLine(WIDTH_CONSTANT, top, imgWidth, top, linePaint);
|
||||
|
||||
hour = endTime/10000;
|
||||
minute = (endTime/100)%100;
|
||||
firstOffset = hour * 60 + minute - minTimeInt; // offset in minutes
|
||||
top = HEIGHT_PROFILE_NAME + HEIGHT_CONSTANT + firstOffset*HEIGHT_MINUTE;
|
||||
text = hour+":"+(minute < 10 ? "0"+minute : minute);
|
||||
canvas.drawText(text, WIDTH_CONSTANT/2, top-textPaintCenter, textPaint);
|
||||
canvas.drawLine(WIDTH_CONSTANT, top, imgWidth, top, linePaint);
|
||||
}
|
||||
|
||||
File outputDir = Environment.getExternalStoragePublicDirectory("Szkolny.eu");
|
||||
outputDir.mkdirs();
|
||||
|
||||
File outputFile = new File(outputDir, "plan_lekcji_"+app.profile.getName()+"_"+Date.getToday().getStringY_m_d()+"_"+Time.getNow().getStringH_M()+".png");
|
||||
|
||||
FileOutputStream fos;
|
||||
try {
|
||||
fos = new FileOutputStream(outputFile);
|
||||
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
fos.close();
|
||||
} catch (Exception e) {
|
||||
Log.e("SAVE_IMAGE", e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
activity.runOnUiThread(() -> {
|
||||
if (progressDialog != null)
|
||||
progressDialog.dismiss();
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.timetable_generate_success_title)
|
||||
.content(R.string.timetable_generate_success_text)
|
||||
.positiveText(R.string.share)
|
||||
.negativeText(R.string.open)
|
||||
.neutralText(R.string.do_nothing)
|
||||
.onPositive(((dialog, which) -> {
|
||||
Uri uri = Uri.parse("file://" + outputFile.getAbsolutePath());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
uri = FileProvider.getUriForFile(activity, app.getPackageName() + ".provider", outputFile);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setDataAndType(null, "image/*");
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.share_intent)));
|
||||
}))
|
||||
.onNegative(((dialog, which) -> {
|
||||
Uri uri = Uri.parse("file://" + outputFile.getAbsolutePath());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
uri = FileProvider.getUriForFile(activity, app.getPackageName() + ".provider", outputFile);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(uri, "image/*");
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
startActivity(intent);
|
||||
}))
|
||||
.show();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static class Adapter extends FragmentPagerAdapter {
|
||||
private final List<Fragment> mFragmentList = new ArrayList<>();
|
||||
private final List<String> mFragmentTitleList = new ArrayList<>();
|
||||
|
||||
public Adapter(FragmentManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return mFragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFragmentList.size();
|
||||
}
|
||||
|
||||
public void addFragment(Fragment fragment, String title) {
|
||||
mFragmentList.add(fragment);
|
||||
mFragmentTitleList.add(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return mFragmentTitleList.get(position);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.timetable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.AsyncTask;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.datamodels.EventFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonChange;
|
||||
import pl.szczodrzynski.edziennik.datamodels.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_HOMEWORK;
|
||||
|
||||
public class TimetableAdapter extends RecyclerView.Adapter<TimetableAdapter.ViewHolder> {
|
||||
private static final String TAG = "TimetableAdapter";
|
||||
private Context context;
|
||||
private Date lessonDate;
|
||||
private List<LessonFull> lessonList;
|
||||
private List<EventFull> eventList;
|
||||
public boolean setAsRead = false;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public TimetableAdapter(Context mCtx, Date lessonDate, List<LessonFull> lessonList, List<EventFull> eventList) {
|
||||
this.context = mCtx;
|
||||
this.lessonDate = lessonDate;
|
||||
this.lessonList = lessonList;
|
||||
this.eventList = eventList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.row_timetable_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
|
||||
LessonFull lesson = lessonList.get(position);
|
||||
holder.timetableItemStartTime.setText(lesson.startTime.getStringHM());
|
||||
holder.timetableItemEndTime.setText(lesson.endTime.getStringHM());
|
||||
holder.timetableItemSubjectName.setText(lesson.subjectLongName);
|
||||
holder.timetableItemClassroomName.setText(lesson.getClassroomName());
|
||||
holder.timetableItemTeamName.setText(lesson.getTeamName());
|
||||
holder.timetableItemTeacherName.setText(lesson.getTeacherFullName());
|
||||
|
||||
holder.timetableItemCard.setCardBackgroundColor(Utils.getAttr(context, R.attr.colorSurface));
|
||||
|
||||
if (lesson.changeId != 0)
|
||||
{
|
||||
if (!lesson.seen) {
|
||||
holder.timetableItemSubjectName.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_4dp));
|
||||
holder.timetableItemSubjectName.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setSeen(App.profileId, lesson, true));
|
||||
}
|
||||
if (lesson.changeType == LessonChange.TYPE_CANCELLED)
|
||||
{
|
||||
holder.timetableItemSubjectName.setTypeface(null, Typeface.NORMAL);
|
||||
holder.timetableItemSubjectChange.setVisibility(View.GONE);
|
||||
|
||||
holder.timetableItemSubjectName.setText(Html.fromHtml("<del>"+lesson.subjectLongName+"</del>", null, new SpannableHtmlTagHandler()));
|
||||
}
|
||||
else if (lesson.changeType == LessonChange.TYPE_CHANGE)
|
||||
{
|
||||
holder.timetableItemSubjectName.setTypeface(null, Typeface.BOLD_ITALIC);
|
||||
if (lesson.changedSubjectLongName()) {
|
||||
holder.timetableItemSubjectChange.setText(lesson.subjectLongName);
|
||||
holder.timetableItemSubjectName.setText(lesson.changeSubjectLongName);
|
||||
holder.timetableItemSubjectChange.setVisibility(View.VISIBLE);
|
||||
|
||||
holder.timetableItemSubjectChange.setText(Html.fromHtml("<del>"+lesson.subjectLongName+"</del>", null, new SpannableHtmlTagHandler()));
|
||||
}
|
||||
else {
|
||||
holder.timetableItemSubjectChange.setVisibility(View.GONE);
|
||||
}
|
||||
holder.timetableItemTeacherName.setText(lesson.getTeacherFullName(true));
|
||||
holder.timetableItemTeamName.setText(lesson.getTeamName(true));
|
||||
holder.timetableItemClassroomName.setText(lesson.getClassroomName(true));
|
||||
}
|
||||
else if (lesson.changeType == LessonChange.TYPE_ADDED)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
holder.timetableItemLayout.getBackground().setColorFilter(new PorterDuffColorFilter(0xffffffff, PorterDuff.Mode.CLEAR));
|
||||
|
||||
if (lesson.changeType == LessonChange.TYPE_CANCELLED) {
|
||||
holder.timetableItemCard.setCardBackgroundColor(Themes.INSTANCE.isDark() ? 0x60000000 : 0xffeeeeee);
|
||||
}
|
||||
else if (lesson.changeType == LessonChange.TYPE_CHANGE) {
|
||||
holder.timetableItemLayout.getBackground().setColorFilter(new PorterDuffColorFilter(Utils.getAttr(context, R.attr.colorPrimary), PorterDuff.Mode.SRC_ATOP));//.setBackgroundColor(App.getAttr(context, R.attr.cardBackgroundHighlight));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
holder.timetableItemLayout.getBackground().setColorFilter(new PorterDuffColorFilter(0xffffffff, PorterDuff.Mode.CLEAR));
|
||||
holder.timetableItemSubjectName.setBackground(null);
|
||||
holder.timetableItemSubjectName.setTypeface(null, Typeface.NORMAL);
|
||||
holder.timetableItemSubjectChange.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
int eventCount = 0;
|
||||
|
||||
for (EventFull event: eventList) {
|
||||
if (event.eventDate.getValue() == lessonDate.getValue()
|
||||
&& event.startTime != null
|
||||
&& event.startTime.getValue() == lesson.startTime.getValue()) {
|
||||
eventCount++;
|
||||
if (eventCount == 1) {
|
||||
holder.timetableItemEvent1.setVisibility(View.VISIBLE);
|
||||
if (event.type == TYPE_HOMEWORK)
|
||||
holder.timetableItemEvent1.setBackground(new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home));
|
||||
else
|
||||
holder.timetableItemEvent1.setBackgroundColor(event.getColor());
|
||||
}
|
||||
else if (eventCount == 2) {
|
||||
holder.timetableItemEvent2.setVisibility(View.VISIBLE);
|
||||
if (event.type == TYPE_HOMEWORK)
|
||||
holder.timetableItemEvent2.setBackground(new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home));
|
||||
else
|
||||
holder.timetableItemEvent2.setBackgroundColor(event.getColor());
|
||||
}
|
||||
else if (eventCount == 3) {
|
||||
holder.timetableItemEvent3.setVisibility(View.VISIBLE);
|
||||
if (event.type == TYPE_HOMEWORK)
|
||||
holder.timetableItemEvent3.setBackground(new IconicsDrawable(context).color(IconicsColor.colorRes(R.color.md_red_500)).size(IconicsSize.dp(10)).icon(CommunityMaterial.Icon2.cmd_home));
|
||||
else
|
||||
holder.timetableItemEvent3.setBackgroundColor(event.getColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
holder.timetableItemCard.setOnClickListener(v -> new EventListDialog(context).show(app, lessonDate, lesson.startTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return lessonList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
CardView timetableItemCard;
|
||||
ConstraintLayout timetableItemLayout;
|
||||
TextView timetableItemStartTime;
|
||||
TextView timetableItemClassroomName;
|
||||
TextView timetableItemTeamName;
|
||||
TextView timetableItemSubjectChange;
|
||||
TextView timetableItemSubjectName;
|
||||
TextView timetableItemTeacherName;
|
||||
TextView timetableItemEndTime;
|
||||
View timetableItemEvent1;
|
||||
View timetableItemEvent2;
|
||||
View timetableItemEvent3;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
timetableItemCard = itemView.findViewById(R.id.timetableItemCard);
|
||||
timetableItemLayout = itemView.findViewById(R.id.timetableItemLayout);
|
||||
timetableItemStartTime = itemView.findViewById(R.id.timetableItemStartTime);
|
||||
timetableItemClassroomName = itemView.findViewById(R.id.timetableItemClassroomName);
|
||||
timetableItemTeamName = itemView.findViewById(R.id.timetableItemTeamName);
|
||||
timetableItemSubjectChange = itemView.findViewById(R.id.timetableItemSubjectChange);
|
||||
timetableItemSubjectName = itemView.findViewById(R.id.timetableItemSubjectName);
|
||||
timetableItemTeacherName = itemView.findViewById(R.id.noticesItemTeacherName);
|
||||
timetableItemEndTime = itemView.findViewById(R.id.timetableItemEndTime);
|
||||
timetableItemEvent1 = itemView.findViewById(R.id.timetableItemEvent1);
|
||||
timetableItemEvent2 = itemView.findViewById(R.id.timetableItemEvent2);
|
||||
timetableItemEvent3 = itemView.findViewById(R.id.timetableItemEvent3);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.webpush;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class QrScannerActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler {
|
||||
private ZXingScannerView mScannerView;
|
||||
public static ZXingScannerView.ResultHandler resultHandler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view
|
||||
setContentView(mScannerView);
|
||||
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
|
||||
mScannerView.startCamera(); // Start camera on resume
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
|
||||
mScannerView.startCamera(); // Start camera on resume
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mScannerView.stopCamera(); // Stop camera on pause
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case 1: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
mScannerView.startCamera();
|
||||
} else {
|
||||
// permission denied, boo! Disable the
|
||||
// functionality that depends on this permission.
|
||||
Toast.makeText(this, R.string.no_permissions, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
// other 'case' lines to check for other
|
||||
// permissions this app might request
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
if (resultHandler != null) {
|
||||
resultHandler.handleResult(rawResult);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
@ -0,0 +1,299 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.webpush;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.Gravity;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityWebPushConfigBinding;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Profile.REGISTRATION_ENABLED;
|
||||
|
||||
public class WebPushConfigActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler {
|
||||
private static final String TAG = "WebPushConfigActivity";
|
||||
private ZXingScannerView mScannerView;
|
||||
|
||||
ActivityWebPushConfigBinding b;
|
||||
|
||||
boolean cameraRunning = false;
|
||||
|
||||
private void showCamera() {
|
||||
cameraRunning = true;
|
||||
Anim.fadeIn(b.qrCodeScanner, 500, null);
|
||||
b.webPushConfig.setVisibility(View.GONE);
|
||||
b.qrCodeScanner.startCamera();
|
||||
b.qrCodeScanner.setResultHandler(this);
|
||||
}
|
||||
|
||||
private App app;
|
||||
|
||||
private void hideCamera() {
|
||||
cameraRunning = false;
|
||||
Anim.fadeOut(b.qrCodeScanner, 500, null);
|
||||
b.webPushConfig.setVisibility(View.VISIBLE);
|
||||
b.qrCodeScanner.stopCamera();
|
||||
}
|
||||
|
||||
private void getPairedBrowsers(@NonNull String newFcm, int removeId) {
|
||||
Anim.fadeIn(b.browserListProgressBar, 500, null);
|
||||
Anim.fadeOut(b.browserList, 500, null);
|
||||
Anim.fadeOut(b.browserListErrorText, 500, null);
|
||||
new ServerRequest(app, app.requestScheme + APP_URL + "main.php?web_push_list"+(!newFcm.equals("") ? "&web_push_pair" : "") + (removeId != -1 ? "&web_push_unpair" : ""), "WebPushConfigActivity", app.profile)
|
||||
.setBodyParameter((removeId != -1 ? "id" : "browser_fcm"), (removeId != -1 ? Integer.toString(removeId) : newFcm))
|
||||
.run(((e, result) -> {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
Anim.fadeOut(b.browserListProgressBar, 500, null);
|
||||
if (result == null || result.get("browser_count") == null) {
|
||||
b.browserListErrorText.setText(R.string.web_push_connection_error);
|
||||
Anim.fadeIn(b.browserListErrorText, 500, null);
|
||||
return;
|
||||
}
|
||||
if (result.get("browser_count").getAsInt() == 0) {
|
||||
b.browserListErrorText.setText(R.string.web_push_no_browsers);
|
||||
Anim.fadeIn(b.browserListErrorText, 500, null);
|
||||
if (app.appConfig.webPushEnabled) {
|
||||
app.appConfig.webPushEnabled = false;
|
||||
app.appConfig.savePending = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
b.browserList.removeAllViews();
|
||||
|
||||
LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
textViewParams.setMargins(0, 0, Utils.dpToPx(8), 0);
|
||||
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
LinearLayout.LayoutParams tableRowParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
|
||||
JsonArray browsers = result.get("browsers").getAsJsonArray();
|
||||
for (JsonElement browserEl: browsers) {
|
||||
JsonObject browser = browserEl.getAsJsonObject();
|
||||
if (browser != null) {
|
||||
//Log.d(TAG, browser.toString());
|
||||
String browserDescription = "(error)";
|
||||
if (browser.get("description") != null) {
|
||||
browserDescription = browser.get("description").getAsString();
|
||||
}
|
||||
int browserId = -1;
|
||||
if (browser.get("id") != null) {
|
||||
browserId = browser.get("id").getAsInt();
|
||||
}
|
||||
|
||||
TableRow browserRow = new TableRow(this);
|
||||
browserRow.setLayoutParams(tableRowParams);
|
||||
|
||||
TextView browserDescriptionText = new TextView(this);
|
||||
//browserDescriptionText.setLayoutParams(textViewParams);
|
||||
browserDescriptionText.setText(browserDescription);
|
||||
browserDescriptionText.setGravity(Gravity.CENTER_VERTICAL);
|
||||
browserRow.addView(browserDescriptionText);
|
||||
|
||||
Button browserRemoveButton = new Button(this, null, android.R.attr.buttonStyleSmall);
|
||||
browserRemoveButton.setMinHeight(0);
|
||||
browserRemoveButton.setText(R.string.remove);
|
||||
int finalBrowserId = browserId;
|
||||
browserRemoveButton.setOnClickListener((v -> {
|
||||
new MaterialDialog.Builder(this)
|
||||
.title(R.string.are_you_sure)
|
||||
.content(R.string.web_push_really_remove)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive(((dialog, which) -> getPairedBrowsers("", finalBrowserId)))
|
||||
.show();
|
||||
}));
|
||||
browserRow.addView(browserRemoveButton/*, buttonParams*/);
|
||||
|
||||
b.browserList.addView(browserRow);
|
||||
}
|
||||
}
|
||||
if (!app.appConfig.webPushEnabled) {
|
||||
app.appConfig.webPushEnabled = true;
|
||||
app.appConfig.savePending = true;
|
||||
}
|
||||
Anim.fadeIn(b.browserList, 500, null);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case 1: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
showCamera();
|
||||
} else {
|
||||
// permission denied, boo! Disable the
|
||||
// functionality that depends on this permission.
|
||||
Toast.makeText(this, R.string.no_permissions, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
// other 'case' lines to check for other
|
||||
// permissions this app might request
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
|
||||
app = (App) getApplicationContext();
|
||||
|
||||
getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_web_push_config, null, false);
|
||||
setContentView(b.getRoot());
|
||||
|
||||
Toolbar toolbar = b.toolbar;
|
||||
toolbar.setTitle(R.string.settings_notification_web_push);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionbar = getSupportActionBar();
|
||||
actionbar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mScannerView = b.qrCodeScanner;
|
||||
List<BarcodeFormat> formats = new ArrayList<>();
|
||||
formats.add(BarcodeFormat.QR_CODE);
|
||||
mScannerView.setFormats(formats);
|
||||
mScannerView.setAspectTolerance(0.5f);
|
||||
|
||||
b.webPushScanNewButton.setOnClickListener((v -> {
|
||||
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
showCamera();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
|
||||
}
|
||||
}));
|
||||
|
||||
if (app.profile.getRegistration() != REGISTRATION_ENABLED) {
|
||||
new MaterialDialog.Builder(this)
|
||||
.title(R.string.web_push_unavailable)
|
||||
.content(R.string.web_push_you_need_to_register)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.what_is_this)
|
||||
.onPositive(((dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}))
|
||||
.onNegative(((dialog, which) -> {
|
||||
new MaterialDialog.Builder(this)
|
||||
.title(R.string.help)
|
||||
.content(R.string.help_notification_web_push)
|
||||
.positiveText(R.string.ok)
|
||||
.show();
|
||||
}))
|
||||
.dismissListener((dialog -> finish()))
|
||||
.autoDismiss(false)
|
||||
.canceledOnTouchOutside(false)
|
||||
.show();
|
||||
b.webPushScanNewButton.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
getPairedBrowsers("", -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// Register ourselves as a handler for scan results.
|
||||
//mScannerView.startCamera(); // Start camera on resume
|
||||
//showCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
hideCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(Result rawResult) {
|
||||
// Do something with the result here
|
||||
//Log.v(TAG, rawResult.getText()); // Prints scan results
|
||||
//Log.v(TAG, rawResult.getBarcodeFormat().toString()); // Prints the scan format (qrcode, pdf417 etc.)
|
||||
|
||||
//Toast.makeText(this, rawResult.getText(), Toast.LENGTH_SHORT).show();
|
||||
|
||||
getPairedBrowsers(rawResult.getText(), -1);
|
||||
|
||||
/*Ion.with(app.getContext())
|
||||
.load(app.requestScheme + APP_URL + "main.php?web_push_pair")
|
||||
.setBodyParameter("username", (app.profile.autoRegistrationAllowed ? app.profile.registrationUsername : app.appConfig.deviceId))
|
||||
.setBodyParameter("app_version_build_type", BuildConfig.BUILD_TYPE)
|
||||
.setBodyParameter("app_version_code", Integer.toString(BuildConfig.VERSION_CODE))
|
||||
.setBodyParameter("app_version", BuildConfig.VERSION_NAME + " " + BuildConfig.BUILD_TYPE + " (" + BuildConfig.VERSION_CODE + ")")
|
||||
.setBodyParameter("device_id", Settings.Secure.getString(app.getContext().getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.setBodyParameter("device_model", Build.MANUFACTURER+" "+Build.MODEL)
|
||||
.setBodyParameter("device_os_version", Build.VERSION.RELEASE)
|
||||
.setBodyParameter("fcm_token", app.appConfig.fcmToken)
|
||||
.setBodyParameter("browser_fcm", rawResult.getText())
|
||||
.asJsonObject()
|
||||
.setCallback((e, result) -> {
|
||||
getPairedBrowsers(-1);
|
||||
});*/
|
||||
|
||||
hideCamera();
|
||||
|
||||
// If you would like to resume scanning, call this method below:
|
||||
//mScannerView.resumeCameraPreview(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
if (cameraRunning) {
|
||||
hideCamera();
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cameraRunning) {
|
||||
hideCamera();
|
||||
return;
|
||||
}
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user