diff --git a/.idea/copyright/Antoni.xml b/.idea/copyright/Antoni.xml
new file mode 100644
index 00000000..438a39d6
--- /dev/null
+++ b/.idea/copyright/Antoni.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
index c4f47e77..affb686f 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt
@@ -25,9 +25,7 @@ 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 com.mikepenz.materialdrawer.model.DividerDrawerItem
-import com.mikepenz.materialdrawer.model.ProfileDrawerItem
-import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
+import com.mikepenz.materialdrawer.model.*
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.model.utils.hiddenInMiniDrawer
import eu.szkolny.font.SzkolnyFont
@@ -77,6 +75,7 @@ import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment
import pl.szczodrzynski.edziennik.ui.notifications.NotificationsListFragment
import pl.szczodrzynski.edziennik.ui.settings.ProfileManagerFragment
import pl.szczodrzynski.edziennik.ui.settings.SettingsFragment
+import pl.szczodrzynski.edziennik.ui.teachers.TeachersListFragment
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
import pl.szczodrzynski.edziennik.ui.webpush.WebPushFragment
import pl.szczodrzynski.edziennik.utils.*
@@ -117,6 +116,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
const val DRAWER_ITEM_ATTENDANCE = 16
const val DRAWER_ITEM_ANNOUNCEMENTS = 18
const val DRAWER_ITEM_NOTIFICATIONS = 20
+ const val DRAWER_ITEM_MORE = 21
+ const val DRAWER_ITEM_TEACHERS = 22
const val DRAWER_ITEM_SETTINGS = 101
const val DRAWER_ITEM_DEBUG = 102
@@ -131,104 +132,137 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val navTargetList: List by lazy {
val list: MutableList = mutableListOf()
+ val moreList: MutableList = mutableListOf()
+
+ moreList += NavTarget(DRAWER_ITEM_TEACHERS,
+ R.string.menu_teachers,
+ TeachersListFragment::class)
+ .withIcon(CommunityMaterial.Icon3.cmd_shield_account_outline)
+ .isStatic(true)
// home item
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
- .withTitle(R.string.app_name)
- .withIcon(CommunityMaterial.Icon2.cmd_home_outline)
- .isInDrawer(true)
- .isStatic(true)
- .withPopToHome(false)
+ .withTitle(R.string.app_name)
+ .withIcon(CommunityMaterial.Icon2.cmd_home_outline)
+ .isInDrawer(true)
+ .isStatic(true)
+ .withPopToHome(false)
- list += NavTarget(DRAWER_ITEM_TIMETABLE, R.string.menu_timetable, TimetableFragment::class)
- .withIcon(CommunityMaterial.Icon3.cmd_timetable)
- .withBadgeTypeId(TYPE_LESSON_CHANGE)
- .isInDrawer(true)
+ list += NavTarget(DRAWER_ITEM_TIMETABLE,
+ R.string.menu_timetable,
+ TimetableFragment::class)
+ .withIcon(CommunityMaterial.Icon3.cmd_timetable)
+ .withBadgeTypeId(TYPE_LESSON_CHANGE)
+ .isInDrawer(true)
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
- .withBadgeTypeId(TYPE_EVENT)
- .isInDrawer(true)
+ .withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
+ .withBadgeTypeId(TYPE_EVENT)
+ .isInDrawer(true)
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class)
- .withIcon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline)
- .withBadgeTypeId(TYPE_GRADE)
- .isInDrawer(true)
+ .withIcon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline)
+ .withBadgeTypeId(TYPE_GRADE)
+ .isInDrawer(true)
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_email_outline)
- .withBadgeTypeId(TYPE_MESSAGE)
- .isInDrawer(true)
+ .withIcon(CommunityMaterial.Icon.cmd_email_outline)
+ .withBadgeTypeId(TYPE_MESSAGE)
+ .isInDrawer(true)
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
- .withIcon(SzkolnyFont.Icon.szf_notebook_outline)
- .withBadgeTypeId(TYPE_HOMEWORK)
- .isInDrawer(true)
+ .withIcon(SzkolnyFont.Icon.szf_notebook_outline)
+ .withBadgeTypeId(TYPE_HOMEWORK)
+ .isInDrawer(true)
- list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
- .withBadgeTypeId(TYPE_NOTICE)
- .isInDrawer(true)
+ list += NavTarget(DRAWER_ITEM_BEHAVIOUR,
+ R.string.menu_notices,
+ BehaviourFragment::class)
+ .withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
+ .withBadgeTypeId(TYPE_NOTICE)
+ .isInDrawer(true)
- list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
- .withBadgeTypeId(TYPE_ATTENDANCE)
- .isInDrawer(true)
+ list += NavTarget(DRAWER_ITEM_ATTENDANCE,
+ R.string.menu_attendance,
+ AttendanceFragment::class)
+ .withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
+ .withBadgeTypeId(TYPE_ATTENDANCE)
+ .isInDrawer(true)
- list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
- .withBadgeTypeId(TYPE_ANNOUNCEMENT)
- .isInDrawer(true)
+ list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS,
+ R.string.menu_announcements,
+ AnnouncementsFragment::class)
+ .withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
+ .withBadgeTypeId(TYPE_ANNOUNCEMENT)
+ .isInDrawer(true)
+
+ list += NavTarget(DRAWER_ITEM_MORE, R.string.menu_more, null)
+ .withIcon(CommunityMaterial.Icon.cmd_dots_horizontal_circle_outline)
+ .isInDrawer(true)
+ .isStatic(true)
+ .withSubItems(*moreList.toTypedArray())
// static drawer items
- list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsListFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
- .isInDrawer(true)
- .isStatic(true)
- .isBelowSeparator(true)
+ list += NavTarget(DRAWER_ITEM_NOTIFICATIONS,
+ R.string.menu_notifications,
+ NotificationsListFragment::class)
+ .withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
+ .isInDrawer(true)
+ .isStatic(true)
+ .isBelowSeparator(true)
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class)
- .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
- .isInDrawer(true)
- .isStatic(true)
- .isBelowSeparator(true)
+ .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
+ .isInDrawer(true)
+ .isStatic(true)
+ .isBelowSeparator(true)
// profile settings items
list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null)
- .withIcon(CommunityMaterial.Icon3.cmd_plus)
- .withDescription(R.string.drawer_add_new_profile_desc)
- .isInProfileList(true)
+ .withIcon(CommunityMaterial.Icon3.cmd_plus)
+ .withDescription(R.string.drawer_add_new_profile_desc)
+ .isInProfileList(true)
- list += NavTarget(DRAWER_PROFILE_MANAGE, R.string.menu_manage_profiles, ProfileManagerFragment::class)
- .withTitle(R.string.title_profile_manager)
- .withIcon(CommunityMaterial.Icon.cmd_account_group)
- .withDescription(R.string.drawer_manage_profiles_desc)
- .isInProfileList(false)
+ list += NavTarget(DRAWER_PROFILE_MANAGE,
+ R.string.menu_manage_profiles,
+ ProfileManagerFragment::class)
+ .withTitle(R.string.title_profile_manager)
+ .withIcon(CommunityMaterial.Icon.cmd_account_group)
+ .withDescription(R.string.drawer_manage_profiles_desc)
+ .isInProfileList(false)
- list += NavTarget(DRAWER_PROFILE_MARK_ALL_AS_READ, R.string.menu_mark_everything_as_read, null)
- .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
- .isInProfileList(true)
+ list += NavTarget(DRAWER_PROFILE_MARK_ALL_AS_READ,
+ R.string.menu_mark_everything_as_read,
+ null)
+ .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
+ .isInProfileList(true)
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
- .withIcon(CommunityMaterial.Icon.cmd_download_outline)
- .isInProfileList(true)
+ .withIcon(CommunityMaterial.Icon.cmd_download_outline)
+ .isInProfileList(true)
// other target items, not directly navigated
- list += NavTarget(TARGET_GRADES_EDITOR, R.string.menu_grades_editor, GradesEditorFragment::class)
+ list += NavTarget(TARGET_GRADES_EDITOR,
+ R.string.menu_grades_editor,
+ GradesEditorFragment::class)
list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
- list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
- list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
+ list += NavTarget(TARGET_MESSAGES_DETAILS,
+ R.string.menu_message,
+ MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
+ list += NavTarget(TARGET_MESSAGES_COMPOSE,
+ R.string.menu_message_compose,
+ MessagesComposeFragment::class)
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
if (App.devMode) {
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
- .withIcon(CommunityMaterial.Icon2.cmd_flask_outline)
- .isInDrawer(true)
- .isBelowSeparator(true)
- .isStatic(true)
+ .withIcon(CommunityMaterial.Icon2.cmd_flask_outline)
+ .isInDrawer(true)
+ .isBelowSeparator(true)
+ .isStatic(true)
}
list
@@ -324,9 +358,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = statusBarColor
}
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ColorUtils.calculateLuminance(statusBarColor) > 0.6) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ && ColorUtils.calculateLuminance(statusBarColor) > 0.6
+ ) {
@Suppress("deprecation")
- window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ window.decorView.systemUiVisibility =
+ window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
// TODO fix navlib navbar detection, orientation change issues, status bar color setting if not fullscreen
@@ -346,8 +383,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fabGravity = Gravity.CENTER
if (Themes.isDark) {
setBackgroundColor(blendColors(
- getColorFromAttr(context, R.attr.colorSurface),
- getColorFromRes(R.color.colorSurface_4dp)
+ getColorFromAttr(context, R.attr.colorSurface),
+ getColorFromRes(R.color.colorSurface_4dp)
))
elevation = dpToPx(4).toFloat()
}
@@ -386,8 +423,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
ProfileConfigDialog(this@MainActivity, appProfile)
}
true
- }
- else {
+ } else {
false
}
}
@@ -408,15 +444,17 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
app.db.profileDao().all.observe(this) { profiles ->
val allArchived = profiles.all { it.archived }
- drawer.setProfileList(profiles.filter { it.id >= 0 && (!it.archived || allArchived) }.toMutableList())
+ drawer.setProfileList(profiles.filter {
+ it.id >= 0 && (!it.archived || allArchived)
+ }.toMutableList())
//prepend the archived profile if loaded
if (app.profile.archived && !allArchived) {
drawer.prependProfile(Profile(
- id = app.profile.id,
- loginStoreId = app.profile.loginStoreId,
- loginStoreType = app.profile.loginStoreType,
- name = app.profile.name,
- subname = "Archiwum - ${app.profile.subname}"
+ id = app.profile.id,
+ loginStoreId = app.profile.loginStoreId,
+ loginStoreType = app.profile.loginStoreType,
+ name = app.profile.name,
+ subname = "Archiwum - ${app.profile.subname}"
).also {
it.archived = true
})
@@ -438,9 +476,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
b.swipeRefreshLayout.isEnabled = true
b.swipeRefreshLayout.setOnRefreshListener { launch { syncCurrentFeature() } }
b.swipeRefreshLayout.setColorSchemeResources(
- R.color.md_blue_500,
- R.color.md_amber_500,
- R.color.md_green_500
+ R.color.md_blue_500,
+ R.color.md_amber_500,
+ R.color.md_green_500
)
SyncWorker.scheduleNext(app)
@@ -470,9 +508,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val today = Date.getToday()
if ((today.month % 11 == 1) && app.config.ui.snowfall) {
b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false))
- }
- else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) {
- val eggfall = layoutInflater.inflate(R.layout.eggfall, b.rootFrame, false) as SnowfallView
+ } else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) {
+ val eggfall = layoutInflater.inflate(
+ R.layout.eggfall,
+ b.rootFrame,
+ false
+ ) as SnowfallView
eggfall.setSnowflakeBitmaps(listOf(
BitmapFactory.decodeResource(resources, R.drawable.egg1),
BitmapFactory.decodeResource(resources, R.drawable.egg2),
@@ -501,65 +542,68 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (app.config.appRateSnackbarTime != 0L && app.config.appRateSnackbarTime <= System.currentTimeMillis()) {
navView.coordinator.postDelayed({
CafeBar.builder(this)
- .content(R.string.rate_snackbar_text)
- .icon(IconicsDrawable(this).apply {
- icon = CommunityMaterial.Icon3.cmd_star_outline
- sizeDp = 24
- colorInt = Themes.getPrimaryTextColor(this@MainActivity)
- })
- .positiveText(R.string.rate_snackbar_positive)
- .positiveColor(-0xb350b0)
- .negativeText(R.string.rate_snackbar_negative)
- .negativeColor(0xff666666.toInt())
- .neutralText(R.string.rate_snackbar_neutral)
- .neutralColor(0xff666666.toInt())
- .onPositive { cafeBar ->
- Utils.openGooglePlay(this)
- cafeBar.dismiss()
- app.config.appRateSnackbarTime = 0
- }
- .onNegative { cafeBar ->
- Toast.makeText(this, R.string.rate_snackbar_negative_message, Toast.LENGTH_LONG).show()
- cafeBar.dismiss()
- app.config.appRateSnackbarTime = 0
- }
- .onNeutral { cafeBar ->
- Toast.makeText(this, R.string.ok, Toast.LENGTH_LONG).show()
- cafeBar.dismiss()
- app.config.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
- }
- .autoDismiss(false)
- .swipeToDismiss(true)
- .floating(true)
- .show()
+ .content(R.string.rate_snackbar_text)
+ .icon(IconicsDrawable(this).apply {
+ icon = CommunityMaterial.Icon3.cmd_star_outline
+ sizeDp = 24
+ colorInt = Themes.getPrimaryTextColor(this@MainActivity)
+ })
+ .positiveText(R.string.rate_snackbar_positive)
+ .positiveColor(-0xb350b0)
+ .negativeText(R.string.rate_snackbar_negative)
+ .negativeColor(0xff666666.toInt())
+ .neutralText(R.string.rate_snackbar_neutral)
+ .neutralColor(0xff666666.toInt())
+ .onPositive { cafeBar ->
+ Utils.openGooglePlay(this)
+ cafeBar.dismiss()
+ app.config.appRateSnackbarTime = 0
+ }
+ .onNegative { cafeBar ->
+ Toast.makeText(this,
+ R.string.rate_snackbar_negative_message,
+ Toast.LENGTH_LONG).show()
+ cafeBar.dismiss()
+ app.config.appRateSnackbarTime = 0
+ }
+ .onNeutral { cafeBar ->
+ Toast.makeText(this, R.string.ok, Toast.LENGTH_LONG).show()
+ cafeBar.dismiss()
+ app.config.appRateSnackbarTime =
+ System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
+ }
+ .autoDismiss(false)
+ .swipeToDismiss(true)
+ .floating(true)
+ .show()
}, 10000)
}
// CONTEXT MENU ITEMS
bottomSheet.removeAllItems()
bottomSheet.appendItems(
- BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_sync)
- .withIcon(CommunityMaterial.Icon.cmd_download_outline)
- .withOnClickListener {
- bottomSheet.close()
- SyncViewListDialog(this, navTargetId)
- },
- BottomSheetSeparatorItem(false),
- BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_settings)
- .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
- .withOnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) },
- BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_feedback)
- .withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
- .withOnClickListener { loadTarget(TARGET_FEEDBACK) }
+ BottomSheetPrimaryItem(false)
+ .withTitle(R.string.menu_sync)
+ .withIcon(CommunityMaterial.Icon.cmd_download_outline)
+ .withOnClickListener {
+ bottomSheet.close()
+ SyncViewListDialog(this, navTargetId)
+ },
+ BottomSheetSeparatorItem(false),
+ BottomSheetPrimaryItem(false)
+ .withTitle(R.string.menu_settings)
+ .withIcon(CommunityMaterial.Icon.cmd_cog_outline)
+ .withOnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) },
+ BottomSheetPrimaryItem(false)
+ .withTitle(R.string.menu_feedback)
+ .withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
+ .withOnClickListener { loadTarget(TARGET_FEEDBACK) }
)
if (App.devMode) {
bottomSheet += BottomSheetPrimaryItem(false)
- .withTitle(R.string.menu_debug)
- .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
- .withOnClickListener { loadTarget(DRAWER_ITEM_DEBUG) }
+ .withTitle(R.string.menu_debug)
+ .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
+ .withOnClickListener { loadTarget(DRAWER_ITEM_DEBUG) }
}
}
@@ -571,17 +615,22 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
DRAWER_PROFILE_SYNC_ALL -> {
EdziennikTask.sync().enqueue(this)
}
- DRAWER_PROFILE_MARK_ALL_AS_READ -> { launch {
- withContext(Dispatchers.Default) {
- app.db.profileDao().allNow.forEach { profile ->
- if (profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS)
- app.db.metadataDao().setAllSeenExceptMessagesAndAnnouncements(profile.id, true)
- else
- app.db.metadataDao().setAllSeenExceptMessages(profile.id, true)
+ DRAWER_PROFILE_MARK_ALL_AS_READ -> {
+ launch {
+ withContext(Dispatchers.Default) {
+ app.db.profileDao().allNow.forEach { profile ->
+ if (profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS)
+ app.db.metadataDao()
+ .setAllSeenExceptMessagesAndAnnouncements(profile.id, true)
+ else
+ app.db.metadataDao().setAllSeenExceptMessages(profile.id, true)
+ }
}
+ Toast.makeText(this@MainActivity,
+ R.string.main_menu_mark_as_read_success,
+ Toast.LENGTH_SHORT).show()
}
- Toast.makeText(this@MainActivity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
- }}
+ }
else -> {
loadTarget(id)
}
@@ -600,36 +649,36 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
private suspend fun syncCurrentFeature() {
if (app.profile.archived) {
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.profile_archived_title)
- .setMessage(
- R.string.profile_archived_text,
- app.profile.studentSchoolYearStart,
- app.profile.studentSchoolYearStart + 1
- )
- .setPositiveButton(R.string.ok, null)
- .show()
+ .setTitle(R.string.profile_archived_title)
+ .setMessage(
+ R.string.profile_archived_text,
+ app.profile.studentSchoolYearStart,
+ app.profile.studentSchoolYearStart + 1
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
swipeRefreshLayout.isRefreshing = false
return
}
if (app.profile.shouldArchive()) {
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.profile_archiving_title)
- .setMessage(
- R.string.profile_archiving_format,
- app.profile.dateYearEnd.formattedString
- )
- .setPositiveButton(R.string.ok, null)
- .show()
+ .setTitle(R.string.profile_archiving_title)
+ .setMessage(
+ R.string.profile_archiving_format,
+ app.profile.dateYearEnd.formattedString
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
}
if (app.profile.isBeforeYear()) {
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.profile_year_not_started_title)
- .setMessage(
- R.string.profile_year_not_started_format,
- app.profile.dateSemester1Start.formattedString
- )
- .setPositiveButton(R.string.ok, null)
- .show()
+ .setTitle(R.string.profile_year_not_started_title)
+ .setMessage(
+ R.string.profile_year_not_started_format,
+ app.profile.dateSemester1Start.formattedString
+ )
+ .setPositiveButton(R.string.ok, null)
+ .show()
swipeRefreshLayout.isRefreshing = false
return
}
@@ -664,16 +713,18 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
else -> null
}
EdziennikTask.syncProfile(
- App.profileId,
- listOf(navTargetId to fragmentParam),
- arguments = arguments
+ App.profileId,
+ listOf(navTargetId to fragmentParam),
+ arguments = arguments
).enqueue(this)
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onUpdateEvent(event: Update) {
EventBus.getDefault().removeStickyEvent(event)
UpdateAvailableDialog(this, event)
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onRegisterAvailabilityEvent(event: RegisterAvailabilityEvent) {
EventBus.getDefault().removeStickyEvent(event)
@@ -682,6 +733,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
RegisterUnavailableDialog(this, error.status!!)
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onApiTaskStartedEvent(event: ApiTaskStartedEvent) {
swipeRefreshLayout.isRefreshing = true
@@ -693,6 +745,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onProfileListEmptyEvent(event: ProfileListEmptyEvent) {
d(TAG, "Profile list is empty. Launch LoginActivity.")
@@ -700,6 +753,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
if (event.profileId == App.profileId) {
@@ -709,11 +763,16 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
subtitle = if (event.progress < 0f)
event.progressText ?: ""
else
- getString(R.string.toolbar_subtitle_syncing_format, event.progress.roundToInt(), event.progressText ?: "")
+ getString(
+ R.string.toolbar_subtitle_syncing_format,
+ event.progress.roundToInt(),
+ event.progressText ?: "",
+ )
}
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskFinishedEvent(event: ApiTaskFinishedEvent) {
EventBus.getDefault().removeStickyEvent(event)
@@ -725,11 +784,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskAllFinishedEvent(event: ApiTaskAllFinishedEvent) {
EventBus.getDefault().removeStickyEvent(event)
swipeRefreshLayout.isRefreshing = false
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
EventBus.getDefault().removeStickyEvent(event)
@@ -746,36 +807,41 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
mainSnackbar.dismiss()
errorSnackbar.addError(event.error).show()
}
+
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
EventBus.getDefault().removeStickyEvent(event)
if (app.config.sync.dontShowAppManagerDialog)
return
MaterialAlertDialogBuilder(this)
- .setTitle(R.string.app_manager_dialog_title)
- .setMessage(R.string.app_manager_dialog_text)
- .setPositiveButton(R.string.ok) { _, _ ->
- try {
- for (intent in appManagerIntentList) {
- if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
- startActivity(intent)
- }
- }
- } catch (e: Exception) {
- try {
- startActivity(Intent(Settings.ACTION_SETTINGS))
- } catch (e: Exception) {
- e.printStackTrace()
- Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show()
+ .setTitle(R.string.app_manager_dialog_title)
+ .setMessage(R.string.app_manager_dialog_text)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ try {
+ for (intent in appManagerIntentList) {
+ if (packageManager.resolveActivity(intent,
+ PackageManager.MATCH_DEFAULT_ONLY) != null
+ ) {
+ startActivity(intent)
}
}
+ } catch (e: Exception) {
+ try {
+ startActivity(Intent(Settings.ACTION_SETTINGS))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT)
+ .show()
+ }
}
- .setNeutralButton(R.string.dont_ask_again) { _, _ ->
- app.config.sync.dontShowAppManagerDialog = true
- }
- .setCancelable(false)
- .show()
+ }
+ .setNeutralButton(R.string.dont_ask_again) { _, _ ->
+ app.config.sync.dontShowAppManagerDialog = true
+ }
+ .setCancelable(false)
+ .show()
}
+
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
app.userActionManager.execute(this, event.profileId, event.type)
@@ -809,11 +875,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
handleIntent(intent?.extras)
}
}
+
fun handleIntent(extras: Bundle?) {
d(TAG, "handleIntent() {")
extras?.keySet()?.forEach { key ->
- d(TAG, " \"$key\": "+extras.get(key))
+ d(TAG, " \"$key\": " + extras.get(key))
}
d(TAG, "}")
@@ -824,9 +891,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val handled = when (extras.getString("action")) {
"serverMessage" -> {
ServerMessageDialog(
- this,
- extras.getString("serverMessageTitle") ?: getString(R.string.app_name),
- extras.getString("serverMessageText") ?: ""
+ this,
+ extras.getString("serverMessageTitle") ?: getString(R.string.app_name),
+ extras.getString("serverMessageText") ?: ""
)
true
}
@@ -836,18 +903,20 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
"userActionRequired" -> {
app.userActionManager.execute(
- this,
- extras.getInt("profileId"),
- extras.getInt("type")
+ this,
+ extras.getInt("profileId"),
+ extras.getInt("type")
)
true
}
"createManualEvent" -> {
- val date = extras.getString("eventDate")?.let { Date.fromY_m_d(it) } ?: Date.getToday()
+ val date = extras.getString("eventDate")
+ ?.let { Date.fromY_m_d(it) }
+ ?: Date.getToday()
EventManualDialog(
- this,
- App.profileId,
- defaultDate = date
+ this,
+ App.profileId,
+ defaultDate = date
)
true
}
@@ -914,9 +983,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
override fun recreate() {
recreate(navTargetId)
}
+
fun recreate(targetId: Int) {
recreate(targetId, null)
}
+
fun recreate(targetId: Int? = null, arguments: Bundle? = null) {
val intent = Intent(this, MainActivity::class.java)
if (arguments != null)
@@ -933,10 +1004,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
d(TAG, "Activity started")
super.onStart()
}
+
override fun onStop() {
d(TAG, "Activity stopped")
super.onStop()
}
+
override fun onResume() {
d(TAG, "Activity resumed")
val filter = IntentFilter()
@@ -945,12 +1018,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
EventBus.getDefault().register(this)
super.onResume()
}
+
override fun onPause() {
d(TAG, "Activity paused")
unregisterReceiver(intentReceiver)
EventBus.getDefault().unregister(this)
super.onPause()
}
+
override fun onDestroy() {
d(TAG, "Activity destroyed")
super.onDestroy()
@@ -979,11 +1054,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
| |___| (_) | (_| | (_| | | | | | | | __/ |_| | | | (_) | (_| \__ \
|______\___/ \__,_|\__,_| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|__*/
val navOptions = NavOptions.Builder()
- .setEnterAnim(R.anim.task_open_enter) // new fragment enter
- .setExitAnim(R.anim.task_open_exit) // old fragment exit
- .setPopEnterAnim(R.anim.task_close_enter) // old fragment enter back
- .setPopExitAnim(R.anim.task_close_exit) // new fragment exit
- .build()
+ .setEnterAnim(R.anim.task_open_enter) // new fragment enter
+ .setExitAnim(R.anim.task_open_exit) // old fragment exit
+ .setPopEnterAnim(R.anim.task_close_enter) // old fragment enter back
+ .setPopExitAnim(R.anim.task_close_exit) // new fragment exit
+ .build()
private fun canNavigate(): Boolean = onBeforeNavigate?.invoke() != false
@@ -1011,6 +1086,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
+
// fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
fun loadProfile(profile: Profile): Boolean {
if (!canNavigate()) {
@@ -1025,6 +1101,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
loadProfile(profile, navTargetId, null)
return true
}
+
private fun loadProfile(
id: Int,
drawerSelection: Int,
@@ -1056,6 +1133,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
return true
}
+
private fun loadProfile(profile: Profile, drawerSelection: Int, arguments: Bundle?) {
App.profile = profile
MessagesFragment.pageSelection = -1
@@ -1069,11 +1147,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
if (profile.archived) {
drawer.prependProfile(Profile(
- id = profile.id,
- loginStoreId = profile.loginStoreId,
- loginStoreType = profile.loginStoreType,
- name = profile.name,
- subname = "Archiwum - ${profile.subname}"
+ id = profile.id,
+ loginStoreId = profile.loginStoreId,
+ loginStoreType = profile.loginStoreType,
+ name = profile.name,
+ subname = "Archiwum - ${profile.subname}"
).also {
it.archived = true
})
@@ -1085,6 +1163,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
drawer.currentProfile = app.profileId
loadTarget(drawerSelection, arguments, skipBeforeNavigate = true)
}
+
fun loadTarget(
id: Int,
arguments: Bundle? = null,
@@ -1094,15 +1173,28 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (loadId == -1) {
loadId = DRAWER_ITEM_HOME
}
- val target = navTargetList
- .firstOrNull { it.id == loadId }
- return if (target == null) {
- Toast.makeText(this, getString(R.string.error_invalid_fragment, id), Toast.LENGTH_LONG).show()
- loadTarget(navTargetList.first(), arguments, skipBeforeNavigate)
- } else {
- loadTarget(target, arguments, skipBeforeNavigate)
+ val targets = navTargetList
+ .flatMap { it.subItems?.toList() ?: emptyList() }
+ .plus(navTargetList)
+ val target = targets.firstOrNull { it.id == loadId }
+ return when {
+ target == null -> {
+ Toast.makeText(
+ this,
+ getString(R.string.error_invalid_fragment, id),
+ Toast.LENGTH_LONG,
+ ).show()
+ loadTarget(navTargetList.first(), arguments, skipBeforeNavigate)
+ }
+ target.fragmentClass != null -> {
+ loadTarget(target, arguments, skipBeforeNavigate)
+ }
+ else -> {
+ false
+ }
}
}
+
private fun loadTarget(
target: NavTarget,
args: Bundle? = null,
@@ -1121,7 +1213,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
pausedNavigationData = null
- val arguments = args ?: navBackStack.firstOrNull { it.first.id == target.id }?.second ?: Bundle()
+ val arguments = args
+ ?: navBackStack.firstOrNull { it.first.id == target.id }?.second
+ ?: Bundle()
bottomSheet.close()
bottomSheet.removeAllContextual()
bottomSheet.toggleGroupEnabled = false
@@ -1133,7 +1227,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
navView.bottomBar.fabExtended = false
navView.bottomBar.setFabOnClickListener(null)
- d("NavDebug", "Navigating from ${navTarget.fragmentClass?.java?.simpleName} to ${target.fragmentClass?.java?.simpleName}")
+ d("NavDebug",
+ "Navigating from ${navTarget.fragmentClass?.java?.simpleName} to ${target.fragmentClass?.java?.simpleName}")
val fragment = target.fragmentClass?.java?.newInstance() ?: return false
fragment.arguments = arguments
@@ -1142,18 +1237,17 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (navTarget == target) {
// just reload the current target
transaction.setCustomAnimations(
- R.anim.fade_in,
- R.anim.fade_out
+ R.anim.fade_in,
+ R.anim.fade_out
)
- }
- else {
+ } else {
navBackStack.keys().lastIndexOf(target).let {
if (it == -1)
return@let target
// pop the back stack up until that target
transaction.setCustomAnimations(
- R.anim.task_close_enter,
- R.anim.task_close_exit
+ R.anim.task_close_enter,
+ R.anim.task_close_exit
)
// navigating grades_add -> grades
@@ -1176,8 +1270,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// target is neither current nor in the back stack
// so navigate to it
transaction.setCustomAnimations(
- R.anim.task_open_enter,
- R.anim.task_open_exit
+ R.anim.task_open_enter,
+ R.anim.task_open_exit
)
navBackStack.add(navTarget to navArguments)
navTarget = target
@@ -1194,7 +1288,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
- d("NavDebug", "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:")
+ d("NavDebug",
+ "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:")
navBackStack.forEachIndexed { index, target2 ->
d("NavDebug", " - $index: ${target2.first.fragmentClass?.java?.simpleName}")
}
@@ -1205,16 +1300,21 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// TASK DESCRIPTION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val bm = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
+
@Suppress("deprecation")
val taskDesc = ActivityManager.TaskDescription(
- if (target.id == HOME_ID) getString(R.string.app_name) else getString(R.string.app_task_format, getString(target.name)),
- bm,
- getColorFromAttr(this, R.attr.colorSurface)
+ if (target.id == HOME_ID)
+ getString(R.string.app_name)
+ else
+ getString(R.string.app_task_format, getString(target.name)),
+ bm,
+ getColorFromAttr(this, R.attr.colorSurface)
)
setTaskDescription(taskDesc)
}
return true
}
+
fun reloadTarget() = loadTarget(navTarget)
private fun popBackStack(skipBeforeNavigate: Boolean = false): Boolean {
@@ -1237,6 +1337,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
return true
}
+
fun navigateUp(skipBeforeNavigate: Boolean = false) {
if (!popBackStack(skipBeforeNavigate)) {
super.onBackPressed()
@@ -1288,29 +1389,31 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|_____/|_| \__,_| \_/\_/ \___|_| |_|\__\___|_| |_| |_|__*/
@Suppress("UNUSED_PARAMETER")
private fun createDrawerItem(target: NavTarget, level: Int = 1): IDrawerItem<*> {
- val item = DrawerPrimaryItem().apply {
- identifier = target.id.toLong()
- nameRes = target.name
- hiddenInMiniDrawer = !app.config.ui.miniMenuButtons.contains(target.id)
- if (target.description != null)
- descriptionRes = target.description!!
- if (target.icon != null)
- withIcon(target.icon!!)
- if (target.title != null)
- appTitle = getString(target.title!!)
- if (target.badgeTypeId != null)
- badgeStyle = drawer.badgeStyle
- isSelectedBackgroundAnimated = false
+ val item = when {
+ target.subItems != null -> ExpandableDrawerItem()
+ level > 1 -> SecondaryDrawerItem()
+ else -> DrawerPrimaryItem()
+ }
+
+ item.also {
+ it.identifier = target.id.toLong()
+ it.nameRes = target.name
+ it.hiddenInMiniDrawer = !app.config.ui.miniMenuButtons.contains(target.id)
+ it.description = target.description?.toStringHolder()
+ it.icon = target.icon?.toImageHolder()
+ if (it is DrawerPrimaryItem)
+ it.appTitle = target.title?.resolveString(this)
+ if (it is ColorfulBadgeable && target.badgeTypeId != null)
+ it.badgeStyle = drawer.badgeStyle
+ it.isSelectedBackgroundAnimated = false
+ it.level = level
}
if (target.badgeTypeId != null)
drawer.addUnreadCounterType(target.badgeTypeId!!, target.id)
- // TODO sub items
- /*
- if (target.subItems != null) {
- for (subItem in target.subItems!!) {
- item.subItems += createDrawerItem(subItem, level+1)
- }
- }*/
+
+ item.subItems = target.subItems?.map {
+ createDrawerItem(it, level + 1)
+ }?.toMutableList() ?: mutableListOf()
return item
}
@@ -1335,7 +1438,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (target.popToHome)
targetPopToHomeList += target.id
- if (target.isInDrawer && (target.isStatic || supportedFragments.isEmpty() || supportedFragments.contains(target.id))) {
+ if (target.isInDrawer && (
+ target.isStatic
+ || supportedFragments.isEmpty()
+ || supportedFragments.contains(target.id))
+ ) {
drawerItems += createDrawerItem(target)
if (target.id == 1) {
targetHomeId = target.id
@@ -1368,7 +1475,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
override fun onBackPressed() {
if (!b.navView.onBackPressed()) {
if (App.config.ui.openDrawerOnBackPressed && ((navTarget.popTo == null && navTarget.popToHome)
- || navTarget.id == DRAWER_ITEM_HOME)) {
+ || navTarget.id == DRAWER_ITEM_HOME)
+ ) {
b.navView.drawer.toggle()
} else {
navigateUp()
@@ -1377,6 +1485,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
fun error(error: ApiError) = errorSnackbar.addError(error).show()
- fun snackbar(text: String, actionText: String? = null, onClick: (() -> Unit)? = null) = mainSnackbar.snackbar(text, actionText, onClick)
+ fun snackbar(
+ text: String,
+ actionText: String? = null,
+ onClick: (() -> Unit)? = null,
+ ) = mainSnackbar.snackbar(text, actionText, onClick)
+
fun snackbarDismiss() = mainSnackbar.dismiss()
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt
index cb0d5a06..1cb7587a 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt
@@ -109,6 +109,7 @@ const val VULCAN_HEBE_ENDPOINT_PUSH_ALL = "api/mobile/push/all"
const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule"
const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes"
const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook"
+const val VULCAN_HEBE_ENDPOINT_TEACHERS = "api/mobile/teacher"
const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam"
const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade"
const val VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY = "api/mobile/grade/summary"
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt
index 2e239a7e..924d7ced 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt
@@ -21,6 +21,7 @@ const val ENDPOINT_VULCAN_HEBE_NOTICES = 3070
const val ENDPOINT_VULCAN_HEBE_ATTENDANCE = 3080
const val ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX = 3090
const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3100
+const val ENDPOINT_VULCAN_HEBE_TEACHERS = 3110
const val ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER = 3200
val VulcanFeatures = listOf(
@@ -83,6 +84,7 @@ val VulcanFeatures = listOf(
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE,
- ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE
+ ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE,
+ ENDPOINT_VULCAN_HEBE_TEACHERS to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE))
)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt
index 0724ca46..6170d817 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt
@@ -27,6 +27,7 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
ENDPOINT_VULCAN_HEBE_NOTICES,
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX,
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT,
+ ENDPOINT_VULCAN_HEBE_TEACHERS,
ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER
)
@@ -103,9 +104,13 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
VulcanHebePushConfig(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK -> {
- data.startProgress(R.string.edziennik_progress_endpoint_teachers)
+ data.startProgress(R.string.edziennik_progress_endpoint_addressbook)
VulcanHebeAddressbook(data, lastSync, onSuccess)
}
+ ENDPOINT_VULCAN_HEBE_TEACHERS -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_teachers)
+ VulcanHebeTeachers(data, lastSync, onSuccess)
+ }
ENDPOINT_VULCAN_HEBE_TIMETABLE -> {
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
VulcanHebeTimetable(data, lastSync, onSuccess)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTeachers.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTeachers.kt
new file mode 100644
index 00000000..f2fdfe40
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTeachers.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Antoni Czaplicki 2021-10-15.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
+
+import pl.szczodrzynski.edziennik.DAY
+import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_TEACHERS
+import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
+import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_TEACHERS
+import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
+import pl.szczodrzynski.edziennik.getString
+
+class VulcanHebeTeachers(
+ override val data: DataVulcan,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit,
+) : VulcanHebe(data, lastSync) {
+ companion object {
+ const val TAG = "VulcanHebeTeachers"
+ }
+
+ init {
+ apiGetList(
+ TAG,
+ VULCAN_HEBE_ENDPOINT_TEACHERS,
+ HebeFilterType.BY_PERIOD,
+ lastSync = lastSync,
+ ) { list, _ ->
+ list.forEach { person ->
+ val name = person.getString("Name")
+ val surname = person.getString("Surname")
+ val displayName = person.getString("DisplayName")
+ val subjectName = person.getString("Description") ?: return@apiGetList
+
+ val teacher = data.getTeacherByFirstLast(
+ name?.plus(" ")?.plus(surname) ?: displayName ?: return@forEach
+ )
+
+ teacher.addSubject(data.getSubject(null, subjectName).id)
+ }
+ data.setSyncNext(ENDPOINT_VULCAN_HEBE_TEACHERS, 2 * DAY)
+ onSuccess(ENDPOINT_VULCAN_HEBE_TEACHERS)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt
index 868a5aef..61a7420b 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt
@@ -43,7 +43,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.*
LibrusLesson::class,
TimetableManual::class,
Metadata::class
-], version = 95)
+], version = 96)
@TypeConverters(
ConverterTime::class,
ConverterDate::class,
@@ -181,6 +181,7 @@ abstract class AppDb : RoomDatabase() {
Migration93(),
Migration94(),
Migration95(),
+ Migration96(),
).allowMainThreadQueries().build()
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Teacher.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Teacher.kt
index d526100d..c0cb2a97 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Teacher.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Teacher.kt
@@ -16,7 +16,7 @@ import pl.szczodrzynski.edziennik.ext.join
import java.util.*
@Entity(tableName = "teachers",
- primaryKeys = ["profileId", "teacherId"])
+ primaryKeys = ["profileId", "teacherId"])
open class Teacher {
companion object {
const val TYPE_TEACHER = 0 // 1
@@ -26,6 +26,7 @@ open class Teacher {
const val TYPE_SECRETARIAT = 4 // 16
const val TYPE_PRINCIPAL = 5 // 32
const val TYPE_SCHOOL_ADMIN = 6 // 64
+
// not teachers
const val TYPE_SPECIALIST = 7 // 128
const val TYPE_SUPER_ADMIN = 10 // 1024
@@ -36,7 +37,8 @@ open class Teacher {
const val TYPE_OTHER = 24 // 16777216
const val IS_TEACHER_MASK = 127
- val types: List by lazy { listOf(
+ val types: List by lazy {
+ listOf(
TYPE_TEACHER,
TYPE_EDUCATOR,
TYPE_PEDAGOGUE,
@@ -51,7 +53,8 @@ open class Teacher {
TYPE_PARENTS_COUNCIL,
TYPE_SCHOOL_PARENTS_COUNCIL,
TYPE_OTHER
- ) }
+ )
+ }
fun typeName(c: Context, type: Int, typeDescription: String? = null): String {
val suffix = typeDescription?.let { " ($typeDescription)" } ?: ""
@@ -94,6 +97,9 @@ open class Teacher {
@ColumnInfo(name = "teacherTypeDescription")
var typeDescription: String? = null
+ @ColumnInfo(name = "teacherSubjects")
+ var subjects = mutableListOf()
+
fun isType(checkingType: Int): Boolean {
return type and (1 shl checkingType) >= 1
}
@@ -105,6 +111,8 @@ open class Teacher {
type = type or (1 shl i)
}
+ fun addSubject(subjectId: Long) = subjects.add(subjectId)
+
fun unsetTeacherType(i: Int) {
type = type and (1 shl i).inv()
}
@@ -128,6 +136,7 @@ open class Teacher {
*/
@Ignore
var recipientDisplayName: CharSequence? = null
+
/**
* Used in Message composing - determining the priority
* of search result, based on the search phrase match
@@ -142,8 +151,6 @@ open class Teacher {
this.id = id
}
-
-
@Ignore
constructor(profileId: Int, id: Long, name: String, surname: String) {
this.profileId = profileId
@@ -170,6 +177,7 @@ open class Teacher {
this.surname = it.surname
this.type = it.type
this.typeDescription = it.typeDescription
+ this.subjects = it.subjects
this.image = it.image
this.recipientDisplayName = it.recipientDisplayName
}
@@ -195,6 +203,7 @@ open class Teacher {
", name='" + name + '\'' +
", surname='" + surname + '\'' +
", type=" + dumpType() +
+ ", subjects=" + subjects.joinToString() +
", typeDescription='" + typeDescription + '\'' +
'}'
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration96.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration96.kt
new file mode 100644
index 00000000..52f77256
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration96.kt
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) Antoni Czaplicki 2021-10-17.
+ */
+
+package pl.szczodrzynski.edziennik.data.db.migration
+
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+
+class Migration96 : Migration(95, 96) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ // teachers - associated subjects list
+ database.execSQL("ALTER TABLE teachers ADD COLUMN teacherSubjects TEXT NOT NULL;")
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/GraphicsExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/GraphicsExtensions.kt
index e9b8b9aa..43000d20 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/GraphicsExtensions.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/GraphicsExtensions.kt
@@ -15,6 +15,8 @@ import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.content.res.ResourcesCompat
+import com.mikepenz.iconics.typeface.IIcon
+import pl.szczodrzynski.navlib.ImageHolder
fun colorFromName(name: String?): Int {
val i = (name ?: "").crc32()
@@ -91,3 +93,5 @@ fun Drawable.setTintColor(color: Int): Drawable {
)
return this
}
+
+fun IIcon.toImageHolder() = ImageHolder(this)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt
index 6de7fc20..ebfb1410 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt
@@ -16,6 +16,8 @@ import android.text.style.ForegroundColorSpan
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import androidx.annotation.PluralsRes
+import androidx.annotation.StringRes
+import com.mikepenz.materialdrawer.holder.StringHolder
fun CharSequence?.isNotNullNorEmpty(): Boolean {
return this != null && this.isNotEmpty()
@@ -336,3 +338,8 @@ fun CharSequence.getWordBounds(position: Int, onlyInWord: Boolean = false): Pair
return null
return rangeStart to rangeEnd
}
+
+fun Int.toStringHolder() = StringHolder(this)
+fun CharSequence.toStringHolder() = StringHolder(this)
+
+fun @receiver:StringRes Int.resolveString(context: Context) = context.getString(this)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeSuggestionAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeSuggestionAdapter.kt
index 4d4a37de..db5072bc 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeSuggestionAdapter.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeSuggestionAdapter.kt
@@ -30,7 +30,7 @@ class MessagesComposeSuggestionAdapter(
private val comparator by lazy { Comparator { o1: Teacher, o2: Teacher -> o1.recipientWeight - o2.recipientWeight } }
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val listItem = convertView ?: LayoutInflater.from(context).inflate(R.layout.messages_compose_suggestion_item, parent, false)
+ val listItem = convertView ?: LayoutInflater.from(context).inflate(R.layout.teacher_item, parent, false)
val teacher = teacherList[position]
val name = listItem.findViewById(R.id.name)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt
new file mode 100644
index 00000000..b859ae88
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) Antoni Czaplicki 2021-10-15.
+ */
+
+package pl.szczodrzynski.edziennik.ui.teachers
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
+import pl.szczodrzynski.edziennik.databinding.TeacherItemBinding
+import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
+import pl.szczodrzynski.edziennik.ui.messages.MessagesUtils.getProfileImage
+import pl.szczodrzynski.edziennik.utils.BetterLink
+import kotlin.coroutines.CoroutineContext
+
+class TeachersAdapter(
+ private val activity: AppCompatActivity,
+ val onItemClick: ((item: Teacher) -> Unit)? = null,
+) : RecyclerView.Adapter(), CoroutineScope {
+ companion object {
+ private const val TAG = "TeachersAdapter"
+ }
+
+ private val app = activity.applicationContext as App
+ // optional: place the manager here
+
+ private val job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ var items = listOf()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val inflater = LayoutInflater.from(activity)
+ val view = TeacherItemBinding.inflate(inflater, parent, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val item = items[position]
+ val b = holder.b
+
+ b.name.text = item.fullName
+ b.image.setImageBitmap(item.image?: getProfileImage(48, 24, 16, 12, 1, item.fullName))
+ var role = item.getTypeText(activity)
+ if (item.subjects.isNotNullNorEmpty()) {
+ val subjects = item.subjects.map { App.db.subjectDao().getByIdNow(App.profileId, it).longName }
+ role = role.plus(": ").plus(subjects.joinToString())
+ }
+ b.type.text = role
+
+ item.fullName.let { name ->
+ BetterLink.attach(
+ b.name,
+ teachers = mapOf(item.id to name)
+ )
+ }
+ }
+
+ override fun getItemCount() = items.size
+
+ class ViewHolder(val b: TeacherItemBinding) : RecyclerView.ViewHolder(b.root)
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersListFragment.kt
new file mode 100644
index 00000000..8c24e111
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersListFragment.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) Antoni Czaplicki 2021-10-15.
+ */
+
+package pl.szczodrzynski.edziennik.ui.teachers
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.LinearLayoutManager
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.databinding.TeachersListFragmentBinding
+import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
+import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
+import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
+import kotlin.coroutines.CoroutineContext
+
+class TeachersListFragment : Fragment(), CoroutineScope {
+ companion object {
+ private const val TAG = "TeachersListFragment"
+ }
+
+ private lateinit var app: App
+ private lateinit var activity: MainActivity
+ private lateinit var b: TeachersListFragmentBinding
+
+ private val job: Job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = job + Dispatchers.Main
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ activity = (getActivity() as MainActivity?) ?: return null
+ context ?: return null
+ app = activity.application as App
+ b = TeachersListFragmentBinding.inflate(inflater)
+ return b.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { startCoroutineTimer(100L) {
+ if (!isAdded) return@startCoroutineTimer
+
+ val adapter = TeachersAdapter(activity)
+
+ app.db.teacherDao().getAllTeachers(App.profileId).observe(this@TeachersListFragment, Observer { items ->
+ if (!isAdded) return@Observer
+
+ // load & configure the adapter
+ adapter.items = items
+ if (items.isNotNullNorEmpty() && b.list.adapter == null) {
+ b.list.adapter = adapter
+ b.list.apply {
+ setHasFixedSize(true)
+ layoutManager = LinearLayoutManager(context)
+ addItemDecoration(SimpleDividerItemDecoration(context))
+ }
+ }
+ adapter.notifyDataSetChanged()
+
+ // show/hide relevant views
+ b.progressBar.isVisible = false
+ if (items.isNullOrEmpty()) {
+ b.list.isVisible = false
+ b.noData.isVisible = true
+ } else {
+ b.list.isVisible = true
+ b.noData.isVisible = false
+ }
+ })
+ }}
+}
diff --git a/app/src/main/res/layout/messages_compose_suggestion_item.xml b/app/src/main/res/layout/teacher_item.xml
similarity index 100%
rename from app/src/main/res/layout/messages_compose_suggestion_item.xml
rename to app/src/main/res/layout/teacher_item.xml
diff --git a/app/src/main/res/layout/teachers_list_fragment.xml b/app/src/main/res/layout/teachers_list_fragment.xml
new file mode 100644
index 00000000..9138b401
--- /dev/null
+++ b/app/src/main/res/layout/teachers_list_fragment.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 32f33a03..6a6e2942 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -656,6 +656,7 @@
Nachricht
Schreiben Sie eine Nachricht
Nachrichten
+ Mehr
Verhalten
Benachrichtigungen
Löschen
@@ -1108,6 +1109,7 @@
Administrator / Superadministrator
Lehrer
Kategorie durchsuchen
+ Keine Lehrer.
Übermorgen
Vorgestern
Bernstein
@@ -1236,4 +1238,6 @@
(Elternteil)
Anwendungsentwickler
Liste der Szkolny-Entwickler
+ Lehrer
+ Addressbuch herunterladen…
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index a971ba01..e6a0294a 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -658,6 +658,7 @@
Message
Compose
Messages
+ More
Behaviour
Notifications
Clear
@@ -1110,6 +1111,7 @@
SuperAdmin
Teacher
Browse category
+ No teachers.
overmorrow
the day before yesterday
Amber
@@ -1372,4 +1374,6 @@
In order to be able to save the generated timetable, you must grant access rights to the device\'s memory.\n\nClick OK to grant permissions.
(Child)
(Parent)
+ Teachers
+ Syncing addressbook…
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 06d89915..fae23749 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -301,6 +301,7 @@
Dzięki niej, aplikacja Szkolny.eu może synchronizować dane z e-dziennikiem. Możesz ją zamknąć, ponieważ w tej chwili nic nie robi.
Usługa synchronizacji
Pobieranie szczegółów konta…
+ Pobieranie listy odbiorców…
Pobieranie ogłoszeń szkolnych…
Pobieranie frekwencji ucznia…
Pobieranie kategorii obecności…
@@ -708,6 +709,7 @@
Wiadomość
Napisz wiadomość
Wiadomości
+ Więcej
Zachowanie
Powiadomienia
Usuń wszystkie
@@ -716,6 +718,7 @@
Ustawienia
Synchronizuj
Synchronizuj wszystkie
+ Nauczyciele
Szablon
Plan lekcji
Edytor planu lekcji
@@ -1180,6 +1183,7 @@
Administrator / SuperAdministrator
Nauczyciel
Przeglądaj kategorię
+ Brak nauczycieli.
pojutrze
przedwczoraj
Bursztynowy