[UI] Improve archive-related UI. Add archived info home card.

This commit is contained in:
Kuba Szczodrzyński 2020-08-25 19:14:11 +02:00
parent 1e3da45340
commit 6c6bc89f57
12 changed files with 299 additions and 67 deletions

View File

@ -42,6 +42,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.viewpager.widget.ViewPager
import com.google.android.gms.security.ProviderInstaller
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
@ -672,6 +673,16 @@ fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
text = context.getString(resid, *formatArgs)
}
fun MaterialAlertDialogBuilder.setTitle(@StringRes resid: Int, vararg formatArgs: Any): MaterialAlertDialogBuilder {
setTitle(context.getString(resid, *formatArgs))
return this
}
fun MaterialAlertDialogBuilder.setMessage(@StringRes resid: Int, vararg formatArgs: Any): MaterialAlertDialogBuilder {
setMessage(context.getString(resid, *formatArgs))
return this
}
fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
return JsonObject().apply {
for (property in properties) {

View File

@ -604,6 +604,46 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
__/ |
|__*/
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()
swipeRefreshLayout.isRefreshing = false
return
}
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()
swipeRefreshLayout.isRefreshing = false
return
}
// vulcan hotfix
if (app.profile.dateYearEnd.month > 6) {
app.profile.dateYearEnd.month = 6
app.profile.dateYearEnd.day = 30
}
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()
}
swipeRefreshLayout.isRefreshing = true
Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
val fragmentParam = when (navTargetId) {

View File

@ -26,7 +26,6 @@ import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.models.Date
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
companion object {
@ -74,6 +73,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
internal fun run(app: App, taskCallback: EdziennikCallback) {
profile?.let { profile ->
// vulcan hotfix
if (profile.dateYearEnd.month > 6) {
profile.dateYearEnd.month = 6
profile.dateYearEnd.day = 30
@ -83,11 +83,11 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
taskCallback.onError(ApiError(TAG, ERROR_PROFILE_ARCHIVED))
return
}
else if (Date.getToday() >= profile.dateYearEnd) {
else if (profile.shouldArchive()) {
d(TAG, "The profile $profileId's year ended on ${profile.dateYearEnd}, archiving")
ProfileArchiver(app, profile)
}
if (Date.getToday() < profile.dateSemester1Start) {
if (profile.isBeforeYear()) {
d(TAG, "The profile $profileId's school year has not started yet; aborting sync")
cancel()
taskCallback.onCompleted()

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-8-25.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik
import android.content.Intent

View File

@ -91,6 +91,9 @@ open class Profile(
@delegate:Ignore
val currentSemester by lazy { dateToSemester(Date.getToday()) }
fun shouldArchive() = Date.getToday() >= dateYearEnd && Date.getToday().year > studentSchoolYearStart
fun isBeforeYear() = Date.getToday() < dateSemester1Start
var disabledNotifications: List<Long>? = null
var lastReceiversSync: Long = 0

View File

@ -33,7 +33,7 @@ class CardItemTouchHelperCallback(private val cardAdapter: HomeCardAdapter, priv
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
removeCard(viewHolder.adapterPosition)
removeCard(viewHolder.adapterPosition, cardAdapter)
cardAdapter.items.removeAt(viewHolder.adapterPosition)
cardAdapter.notifyItemRemoved(viewHolder.adapterPosition)
}

View File

@ -28,10 +28,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.ui.dialogs.home.StudentNumberDialog
import pl.szczodrzynski.edziennik.ui.modules.home.cards.HomeEventsCard
import pl.szczodrzynski.edziennik.ui.modules.home.cards.HomeGradesCard
import pl.szczodrzynski.edziennik.ui.modules.home.cards.HomeLuckyNumberCard
import pl.szczodrzynski.edziennik.ui.modules.home.cards.HomeTimetableCard
import pl.szczodrzynski.edziennik.ui.modules.home.cards.*
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
@ -44,8 +41,8 @@ class HomeFragment : Fragment(), CoroutineScope {
fun swapCards(fromPosition: Int, toPosition: Int, cardAdapter: HomeCardAdapter): Boolean {
val fromCard = cardAdapter.items[fromPosition]
val toCard = cardAdapter.items[toPosition]
if (fromCard.id == 100 || toCard.id == 100) {
// debug card is not swappable
if (fromCard.id >= 100 || toCard.id >= 100) {
// debug & archive cards are not swappable
return false
}
cardAdapter.items[fromPosition] = cardAdapter.items[toPosition]
@ -60,10 +57,16 @@ class HomeFragment : Fragment(), CoroutineScope {
return true
}
fun removeCard(position: Int) {
fun removeCard(position: Int, cardAdapter: HomeCardAdapter) {
val homeCards = App.config.forProfile().ui.homeCards.toMutableList()
if (position >= homeCards.size)
return
val card = cardAdapter.items[position]
if (card.id >= 100) {
// debug & archive cards are not removable
cardAdapter.notifyDataSetChanged()
return
}
homeCards.removeAt(position)
App.config.forProfile().ui.homeCards = homeCards
}
@ -160,6 +163,8 @@ class HomeFragment : Fragment(), CoroutineScope {
}
//if (App.devMode)
// items += HomeDebugCard(100, app, activity, this, app.profile)
if (app.profile.archived)
items.add(0, HomeArchiveCard(101, app, activity, this, app.profile))
val adapter = HomeCardAdapter(items)
val itemTouchHelper = ItemTouchHelper(CardItemTouchHelperCallback(adapter, b.refreshLayout))

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-8-25.
*/
package pl.szczodrzynski.edziennik.ui.modules.home.cards
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.plusAssign
import androidx.core.view.setMargins
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.databinding.CardHomeArchiveBinding
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCard
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardAdapter
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
import kotlin.coroutines.CoroutineContext
class HomeArchiveCard(
override val id: Int,
val app: App,
val activity: MainActivity,
val fragment: HomeFragment,
val profile: Profile
) : HomeCard, CoroutineScope {
companion object {
private const val TAG = "HomeArchiveCard"
}
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun bind(position: Int, holder: HomeCardAdapter.ViewHolder) {
holder.root.removeAllViews()
val b = CardHomeArchiveBinding.inflate(LayoutInflater.from(holder.root.context))
b.root.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
setMargins(8.dp)
}
holder.root += b.root
b.homeArchiveText.setText(
R.string.home_archive_text,
profile.studentSchoolYearStart,
profile.studentSchoolYearStart + 1
)
b.homeArchiveClose.onClick {
launch {
val profile = profile.archiveId?.let {
withContext(Dispatchers.IO) {
app.db.profileDao().getNotArchivedOf(it)
}
}
if (profile == null) {
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.home_archive_close_no_target_title)
.setMessage(R.string.home_archive_close_no_target_text, this@HomeArchiveCard.profile.name)
.setPositiveButton(R.string.ok) { _, _ ->
activity.drawer.profileSelectionOpen()
activity.drawer.open()
}
.show()
return@launch
}
activity.loadProfile(profile)
}
}
holder.root.onClick {
activity.loadTarget(MainActivity.DRAWER_ITEM_AGENDA)
}
}
override fun unbind(position: Int, holder: HomeCardAdapter.ViewHolder) = Unit
}

View File

@ -0,0 +1,19 @@
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-8-25.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M54,19H10v33c0,2.209 1.791,4 4,4h36c2.209,0 4,-1.791 4,-4V19z"
android:fillColor="#ffb86b"/>
<path
android:pathData="m54,22h-44c-1.657,0 -3,-1.343 -3,-3v-5c0,-1.657 1.343,-3 3,-3h44c1.657,0 3,1.343 3,3v5c0,1.657 -1.343,3 -3,3z"
android:fillColor="#ffa54a"/>
<path
android:pathData="m37,32h-10c-1.65,0 -3,-1.35 -3,-3s1.35,-3 3,-3h10c1.65,0 3,1.35 3,3s-1.35,3 -3,3z"
android:fillColor="#69707e"/>
</vector>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-8-25.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:layout_margin="8dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_archive_title"
android:textAppearance="@style/NavView.TextView.Title" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/homeArchiveText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="16dp"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal"
android:text="@string/home_archive_text"
android:textSize="16sp"
tools:text="Przeglądasz dane ucznia z roku szkolnego 2019/2020." />
<com.google.android.material.button.MaterialButton
android:id="@+id/homeArchiveClose"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/home_archive_close" />
</LinearLayout>
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
app:srcCompat="@drawable/ic_archive" />
</LinearLayout>
</layout>

View File

@ -17,121 +17,130 @@
android:id="@+id/noTimetableLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
app:srcCompat="@drawable/ic_sync"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Title"
android:text="@string/home_timetable_no_timetable" />
android:text="@string/home_timetable_no_timetable"
android:textAppearance="@style/NavView.TextView.Title" />
<TextView
android:id="@+id/noTimetableText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="@string/home_timetable_no_timetable_text"/>
android:layout_gravity="center_horizontal"
android:layout_margin="16dp"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal"
android:text="@string/home_timetable_no_timetable_text"
android:textSize="16sp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/noTimetableSync"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:text="@string/home_timetable_no_timetable_sync" />
</LinearLayout>
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
app:srcCompat="@drawable/ic_sync" />
</LinearLayout>
<LinearLayout
android:id="@+id/noLessonsLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
tools:layout_marginTop="150dp"
tools:layout_marginTop="170dp"
tools:visibility="visible">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
app:srcCompat="@drawable/ic_timetable"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Title"
android:text="@string/home_timetable_no_lessons" />
android:text="@string/home_timetable_no_lessons"
android:textAppearance="@style/NavView.TextView.Title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="@string/home_timetable_no_lessons_text"/>
android:layout_gravity="center_horizontal"
android:layout_margin="16dp"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal"
android:text="@string/home_timetable_no_lessons_text"
android:textSize="16sp" />
</LinearLayout>
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
app:srcCompat="@drawable/ic_timetable" />
</LinearLayout>
<LinearLayout
android:id="@+id/notPublicLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone"
tools:layout_marginTop="220dp"
tools:layout_marginTop="270dp"
tools:visibility="visible">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
app:srcCompat="@drawable/ic_no_timetable"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Title"
android:text="@string/home_timetable_not_public" />
android:text="@string/home_timetable_not_public"
android:textAppearance="@style/NavView.TextView.Title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="@string/home_timetable_not_public_text"/>
android:layout_gravity="center_horizontal"
android:layout_margin="16dp"
android:fontFamily="sans-serif-light"
android:gravity="center_horizontal"
android:text="@string/home_timetable_not_public_text"
android:textSize="16sp" />
</LinearLayout>
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
app:srcCompat="@drawable/ic_no_timetable" />
</LinearLayout>
<LinearLayout
@ -139,7 +148,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_marginTop="350dp">
tools:layout_marginTop="410dp">
<LinearLayout
android:layout_width="match_parent"
@ -165,15 +174,14 @@
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="7 lekcji - 8:10 do 14:45" />
</LinearLayout>
<ImageView
android:id="@+id/settings"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
android:background="?selectableItemBackgroundBorderless"
android:padding="10dp"
android:visibility="gone"
tools:src="@sample/settings" />
@ -181,16 +189,16 @@
android:id="@+id/bellSync"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
android:background="?selectableItemBackgroundBorderless"
android:padding="10dp"
tools:src="@sample/settings" />
<ImageView
android:id="@+id/showCounter"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
android:background="?selectableItemBackgroundBorderless"
android:padding="10dp"
tools:src="@sample/settings" />
</LinearLayout>
@ -234,10 +242,9 @@
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:visibility="gone"
tools:visibility="visible"
tools:max="2700"
tools:progress="780" />
tools:progress="780"
tools:visibility="visible" />
</LinearLayout>
<TextView
@ -247,7 +254,6 @@
android:layout_gravity="center_vertical"
android:gravity="center"
tools:text="zostały\n2 minuty\n35 sekund" />
</LinearLayout>
<View
@ -263,8 +269,6 @@
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="Póżniej:\n9:05 informatyka\n10:00 urządzenia techniki komputerowej\n11:00 projektowanie lokalnych sieci komputerowych\n11:55 zajęcia z wychowawcą\n13:00 język polski\n14:05 język niemiecki" />
</LinearLayout>
</FrameLayout>
</layout>

View File

@ -1356,4 +1356,15 @@
<string name="login_mode_podlasie_api">Zaloguj używając tokenu</string>
<string name="login_mode_podlasie_api_guide">Podaj token aplikacji mobilnej.</string>
<string name="edziennik_progress_login_podlasie_api">Logowanie do PPE…</string>
<string name="profile_archived_title">Profil jest archiwalny</string>
<string name="profile_archived_text">Przeglądasz dane ucznia z poprzedniego roku szkolnego (%d/%d). Synchronizacja oraz pobieranie wiadomości i niektórych zadań domowych zostały wyłączone.\n\nAby otworzyć profil ucznia z aktualnego roku, wybierz "Zamknij archiwum" na stronie głównej.</string>
<string name="profile_year_not_started_title">Wakacje ;)</string>
<string name="profile_year_not_started_format">Prawdopodobnie rok szkolny dla tego ucznia jeszcze się nie zaczął (zacznie się %s). Spróbuj wykonać synchronizację później.</string>
<string name="profile_archiving_title">Koniec roku szkolnego</string>
<string name="profile_archiving_format">Rok szkolny zakończył się %s. Dane ucznia z poprzedniego roku zostaną przeniesione do archiwum, aby można było je później przeglądać.</string>
<string name="home_archive_title">Profil archiwalny</string>
<string name="home_archive_text">Przeglądasz dane ucznia z roku szkolnego %d/%d.</string>
<string name="home_archive_close">Zamknij archiwum</string>
<string name="home_archive_close_no_target_title">Brak aktualnego profilu</string>
<string name="home_archive_close_no_target_text">Uczeń %s nie posiada profilu na tym koncie w aktualnym roku szkolnym. Prawdopodobnie ten profil został usunięty lub uczeń nie uczęszcza już do tej klasy.\n\nAby przejść do aktualnego profilu, wybierz ucznia z listy lub zaloguj się na jego konto przyciskiem Dodaj ucznia.</string>
</resources>