1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-19 21:49:08 -05:00

Add admin message to LoginStudentSelect and LoginSymbol (#2531)

Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
This commit is contained in:
Rafał Borcz 2024-05-01 16:57:31 +02:00 committed by GitHub
parent e1a19be06c
commit 71ab9586ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 180 additions and 4 deletions

View File

@ -4,6 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.data.serializers.SafeMessageTypeEnumListSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@ -34,6 +36,8 @@ data class AdminMessage(
val priority: String,
@SerialName("messageTypes")
@Serializable(with = SafeMessageTypeEnumListSerializer::class)
@ColumnInfo(name = "types", defaultValue = "[]")
val types: List<MessageType> = emptyList(),

View File

@ -4,6 +4,8 @@ enum class MessageType {
GENERAL_MESSAGE,
DASHBOARD_MESSAGE,
LOGIN_MESSAGE,
LOGIN_STUDENT_SELECT_MESSAGE,
LOGIN_SYMBOL_MESSAGE,
PASS_RESET_MESSAGE,
ERROR_OVERRIDE,
}

View File

@ -0,0 +1,27 @@
package io.github.wulkanowy.data.serializers
import io.github.wulkanowy.data.enums.MessageType
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@OptIn(ExperimentalSerializationApi::class)
object SafeMessageTypeEnumListSerializer : KSerializer<List<MessageType>> {
private val serializer = ListSerializer(String.serializer())
override val descriptor = serializer.descriptor
override fun serialize(encoder: Encoder, value: List<MessageType>) {
encoder.encodeNotNullMark()
serializer.serialize(encoder, value.map { it.name })
}
override fun deserialize(decoder: Decoder): List<MessageType> =
serializer.deserialize(decoder).mapNotNull { enumName ->
MessageType.entries.find { it.name == enumName }
}
}

View File

@ -6,10 +6,12 @@ import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog
@ -111,6 +113,19 @@ class LoginStudentSelectFragment :
LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog")
}
override fun showAdminMessage(adminMessage: AdminMessage?) {
AdminMessageViewHolder(
binding = binding.loginStudentSelectAdminMessage,
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
onAdminMessageClickListener = presenter::onAdminMessageSelected,
).bind(adminMessage)
binding.loginStudentSelectAdminMessage.root.isVisible = adminMessage != null
}
override fun openInternetBrowser(url: String) {
requireContext().openInternetBrowser(url)
}
override fun onDestroyView() {
presenter.onDetachView()
super.onDestroyView()

View File

@ -2,16 +2,23 @@ package io.github.wulkanowy.ui.modules.login.studentselect
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.data.flatResourceFlow
import io.github.wulkanowy.data.logResourceStatus
import io.github.wulkanowy.data.mappers.mapToStudentWithSemesters
import io.github.wulkanowy.data.onResourceData
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.pojos.RegisterStudent
import io.github.wulkanowy.data.pojos.RegisterSymbol
import io.github.wulkanowy.data.pojos.RegisterUnit
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SchoolsRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.resourceFlow
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
import io.github.wulkanowy.sdk.scrapper.exception.StudentGraduateException
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
import io.github.wulkanowy.services.sync.SyncManager
@ -33,6 +40,8 @@ class LoginStudentSelectPresenter @Inject constructor(
private val syncManager: SyncManager,
private val analytics: AnalyticsHelper,
private val appInfo: AppInfo,
private val preferencesRepository: PreferencesRepository,
private val getAppropriateAdminMessageUseCase: GetAppropriateAdminMessageUseCase
) : BasePresenter<LoginStudentSelectView>(loginErrorHandler, studentRepository) {
private var lastError: Throwable? = null
@ -65,6 +74,7 @@ class LoginStudentSelectPresenter @Inject constructor(
this.loginData = loginData
this.registerUser = registerUser
loadData()
loadAdminMessage()
}
private fun loadData() {
@ -88,7 +98,20 @@ class LoginStudentSelectPresenter @Inject constructor(
refreshItems()
}
}
}.launch()
}.launch("load_data")
}
private fun loadAdminMessage() {
flatResourceFlow {
getAppropriateAdminMessageUseCase(
scrapperBaseUrl = registerUser.scrapperBaseUrl.orEmpty(),
type = MessageType.LOGIN_STUDENT_SELECT_MESSAGE,
)
}
.logResourceStatus("load login admin message")
.onResourceData { view?.showAdminMessage(it) }
.onResourceError { view?.showAdminMessage(null) }
.launch("load_admin_message")
}
private fun getStudentsWithCurrentlyActiveSemesters(): List<LoginStudentSelectItem.Student> {
@ -341,4 +364,14 @@ class LoginStudentSelectPresenter @Inject constructor(
)
}
}
fun onAdminMessageSelected(url: String?) {
url?.let { view?.openInternetBrowser(it) }
}
fun onAdminMessageDismissed(adminMessage: AdminMessage) {
preferencesRepository.dismissedAdminMessageIds += adminMessage.id
view?.showAdminMessage(null)
}
}

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.login.studentselect
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.ui.base.BaseView
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
@ -25,4 +26,8 @@ interface LoginStudentSelectView : BaseView {
fun openDiscordInvite()
fun openEmail(supportInfo: LoginSupportInfo)
fun showAdminMessage(adminMessage: AdminMessage?)
fun openInternetBrowser(url: String)
}

View File

@ -9,13 +9,16 @@ import android.view.inputmethod.EditorInfo.IME_NULL
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog
@ -179,4 +182,17 @@ class LoginSymbolFragment :
override fun openSupportDialog(supportInfo: LoginSupportInfo) {
LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog")
}
override fun showAdminMessage(adminMessage: AdminMessage?) {
AdminMessageViewHolder(
binding = binding.loginSymbolAdminMessage,
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
onAdminMessageClickListener = presenter::onAdminMessageSelected,
).bind(adminMessage)
binding.loginSymbolAdminMessage.root.isVisible = adminMessage != null
}
override fun openInternetBrowser(url: String) {
requireContext().openInternetBrowser(url)
}
}

View File

@ -2,10 +2,18 @@ package io.github.wulkanowy.ui.modules.login.symbol
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.data.flatResourceFlow
import io.github.wulkanowy.data.logResourceStatus
import io.github.wulkanowy.data.onResourceData
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.onResourceNotLoading
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.resourceFlow
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
import io.github.wulkanowy.ui.base.BasePresenter
@ -21,7 +29,9 @@ import javax.inject.Inject
class LoginSymbolPresenter @Inject constructor(
studentRepository: StudentRepository,
private val loginErrorHandler: LoginErrorHandler,
private val analytics: AnalyticsHelper
private val analytics: AnalyticsHelper,
private val preferencesRepository: PreferencesRepository,
private val getAppropriateAdminMessageUseCase: GetAppropriateAdminMessageUseCase,
) : BasePresenter<LoginSymbolView>(loginErrorHandler, studentRepository) {
private var lastError: Throwable? = null
@ -43,6 +53,21 @@ class LoginSymbolPresenter @Inject constructor(
clearAndFocusSymbol()
showSoftKeyboard()
}
loadAdminMessage()
}
private fun loadAdminMessage() {
flatResourceFlow {
getAppropriateAdminMessageUseCase(
scrapperBaseUrl = loginData.baseUrl,
type = MessageType.LOGIN_SYMBOL_MESSAGE,
)
}
.logResourceStatus("load login admin message")
.onResourceData { view?.showAdminMessage(it) }
.onResourceError { view?.showAdminMessage(null) }
.launch("load_admin_message")
}
fun onSymbolTextChanged() {
@ -166,4 +191,14 @@ class LoginSymbolPresenter @Inject constructor(
)
)
}
fun onAdminMessageSelected(url: String?) {
url?.let { view?.openInternetBrowser(it) }
}
fun onAdminMessageDismissed(adminMessage: AdminMessage) {
preferencesRepository.dismissedAdminMessageIds += adminMessage.id
view?.showAdminMessage(null)
}
}

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.login.symbol
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.ui.base.BaseView
import io.github.wulkanowy.ui.modules.login.LoginData
@ -44,4 +45,8 @@ interface LoginSymbolView : BaseView {
fun openFaqPage()
fun openSupportDialog(supportInfo: LoginSupportInfo)
fun showAdminMessage(adminMessage: AdminMessage?)
fun openInternetBrowser(url: String)
}

View File

@ -11,6 +11,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/login_student_select_admin_message"
layout="@layout/item_dashboard_admin_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:visibility="visible" />
<TextView
android:id="@+id/loginStudentSelectHeader"
android:layout_width="match_parent"
@ -28,7 +40,7 @@
app:layout_constraintBottom_toTopOf="@id/loginStudentSelectRecycler"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@id/login_student_select_admin_message"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.recyclerview.widget.RecyclerView

View File

@ -95,6 +95,18 @@
android:background="?android:attr/listDivider" />
</LinearLayout>
<include
android:id="@+id/login_symbol_admin_message"
layout="@layout/item_dashboard_admin_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/loginSymbolContact"
app:layout_constraintVertical_chainStyle="packed"
tools:visibility="visible" />
<TextView
android:id="@+id/loginSymbolHeader"
android:layout_width="match_parent"
@ -111,7 +123,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginSymbolContact"
app:layout_constraintTop_toBottomOf="@+id/login_symbol_admin_message"
app:layout_constraintVertical_chainStyle="packed" />
<TextView

View File

@ -5,8 +5,10 @@ import io.github.wulkanowy.data.pojos.RegisterStudent
import io.github.wulkanowy.data.pojos.RegisterSymbol
import io.github.wulkanowy.data.pojos.RegisterUnit
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SchoolsRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.scrapper.Scrapper
import io.github.wulkanowy.services.sync.SyncManager
@ -44,6 +46,12 @@ class LoginStudentSelectPresenterTest {
@MockK
lateinit var schoolsRepository: SchoolsRepository
@MockK
lateinit var preferencesRepository: PreferencesRepository
@MockK
lateinit var getAppropriateAdminMessageUseCase: GetAppropriateAdminMessageUseCase
@MockK(relaxed = true)
lateinit var analytics: AnalyticsHelper
@ -132,6 +140,8 @@ class LoginStudentSelectPresenterTest {
syncManager = syncManager,
analytics = analytics,
appInfo = appInfo,
preferencesRepository = preferencesRepository,
getAppropriateAdminMessageUseCase = getAppropriateAdminMessageUseCase
)
}