[UI/Messages] Add greeting text configuration dialog.

This commit is contained in:
Kuba Szczodrzyński 2021-04-14 21:08:27 +02:00
parent 1e8fb6a9ae
commit 47ec1899a1
No known key found for this signature in database
GPG Key ID: 70CB8A85BA1633CB
9 changed files with 239 additions and 11 deletions

View File

@ -19,4 +19,24 @@ class ProfileConfigUI(private val config: ProfileConfig) {
var homeCards: List<HomeCardModel> var homeCards: List<HomeCardModel>
get() { mHomeCards = mHomeCards ?: config.values.get("homeCards", listOf(), HomeCardModel::class.java); return mHomeCards ?: listOf() } get() { mHomeCards = mHomeCards ?: config.values.get("homeCards", listOf(), HomeCardModel::class.java); return mHomeCards ?: listOf() }
set(value) { config.set("homeCards", value); mHomeCards = value } set(value) { config.set("homeCards", value); mHomeCards = value }
private var mMessagesGreetingOnCompose: Boolean? = null
var messagesGreetingOnCompose: Boolean
get() { mMessagesGreetingOnCompose = mMessagesGreetingOnCompose ?: config.values.get("messagesGreetingOnCompose", true); return mMessagesGreetingOnCompose ?: true }
set(value) { config.set("messagesGreetingOnCompose", value); mMessagesGreetingOnCompose = value }
private var mMessagesGreetingOnReply: Boolean? = null
var messagesGreetingOnReply: Boolean
get() { mMessagesGreetingOnReply = mMessagesGreetingOnReply ?: config.values.get("messagesGreetingOnReply", true); return mMessagesGreetingOnReply ?: true }
set(value) { config.set("messagesGreetingOnReply", value); mMessagesGreetingOnReply = value }
private var mMessagesGreetingOnForward: Boolean? = null
var messagesGreetingOnForward: Boolean
get() { mMessagesGreetingOnForward = mMessagesGreetingOnForward ?: config.values.get("messagesGreetingOnForward", false); return mMessagesGreetingOnForward ?: false }
set(value) { config.set("messagesGreetingOnForward", value); mMessagesGreetingOnForward = value }
private var mMessagesGreetingText: String? = null
var messagesGreetingText: String?
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
} }

View File

@ -129,6 +129,9 @@ open class Profile(
val isParent val isParent
get() = accountName != null get() = accountName != null
val accountOwnerName
get() = accountName ?: studentNameLong
val registerName val registerName
get() = when (loginStoreType) { get() = when (loginStoreType) {
LOGIN_TYPE_LIBRUS -> "librus" LOGIN_TYPE_LIBRUS -> "librus"

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-4-14.
*/
package pl.szczodrzynski.edziennik.ui.dialogs
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.MessagesConfigDialogBinding
class MessagesConfigDialog(
private val activity: AppCompatActivity,
private val reloadOnDismiss: Boolean = true,
private val onShowListener: ((tag: String) -> Unit)? = null,
private val onDismissListener: ((tag: String) -> Unit)? = null
) {
companion object {
const val TAG = "MessagesConfigDialog"
}
private val app by lazy { activity.application as App }
private val config by lazy { app.config.ui }
private val profileConfig by lazy { app.config.forProfile().ui }
private lateinit var b: MessagesConfigDialogBinding
private lateinit var dialog: AlertDialog
init { run {
if (activity.isFinishing)
return@run
b = MessagesConfigDialogBinding.inflate(activity.layoutInflater)
onShowListener?.invoke(TAG)
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.menu_messages_config)
.setView(b.root)
.setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
.setOnDismissListener {
saveConfig()
onDismissListener?.invoke(TAG)
if (reloadOnDismiss) (activity as? MainActivity)?.reloadTarget()
}
.create()
loadConfig()
dialog.show()
}}
private fun loadConfig() {
b.config = profileConfig
b.greetingText.setText(
profileConfig.messagesGreetingText ?: "\n\nZ poważaniem\n${app.profile.accountOwnerName}"
)
}
private fun saveConfig() {
val greetingText = b.greetingText.text?.toString()?.trim()
if (greetingText.isNullOrEmpty())
profileConfig.messagesGreetingText = null
else
profileConfig.messagesGreetingText = "\n\n$greetingText"
}
}

View File

@ -30,10 +30,12 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.databinding.MessageFragmentBinding import pl.szczodrzynski.edziennik.databinding.MessageFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.MessagesConfigDialog
import pl.szczodrzynski.edziennik.utils.Anim import pl.szczodrzynski.edziennik.utils.Anim
import pl.szczodrzynski.edziennik.utils.BetterLink import pl.szczodrzynski.edziennik.utils.BetterLink
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.colorAttr import pl.szczodrzynski.navlib.colorAttr
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.math.min import kotlin.math.min
@ -64,10 +66,20 @@ class MessageFragment : Fragment(), CoroutineScope {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded) return if (!isAdded) return
activity.bottomSheet.prependItem(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_messages_config)
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
MessagesConfigDialog(activity, false, null, null)
}
)
b.closeButton.setImageDrawable( b.closeButton.setImageDrawable(
IconicsDrawable(activity, CommunityMaterial.Icon3.cmd_window_close).apply { IconicsDrawable(activity, CommunityMaterial.Icon3.cmd_window_close).apply {
colorAttr(activity, android.R.attr.textColorSecondary) colorAttr(activity, android.R.attr.textColorSecondary)
sizeDp = 16 sizeDp = 24
} }
) )
b.closeButton.setOnClickListener { activity.navigateUp() } b.closeButton.setOnClickListener { activity.navigateUp() }

View File

@ -12,7 +12,9 @@ import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.databinding.MessagesFragmentBinding import pl.szczodrzynski.edziennik.databinding.MessagesFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.MessagesConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class MessagesFragment : Fragment(), CoroutineScope { class MessagesFragment : Fragment(), CoroutineScope {
@ -100,9 +102,19 @@ class MessagesFragment : Fragment(), CoroutineScope {
fabIcon = CommunityMaterial.Icon3.cmd_pencil_outline fabIcon = CommunityMaterial.Icon3.cmd_pencil_outline
} }
setFabOnClickListener(View.OnClickListener { bottomSheet.prependItem(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_messages_config)
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
MessagesConfigDialog(activity, false, null, null)
}
)
setFabOnClickListener {
activity.loadTarget(MainActivity.TARGET_MESSAGES_COMPOSE) activity.loadTarget(MainActivity.TARGET_MESSAGES_COMPOSE)
}) }
} }
activity.gainAttentionFAB() activity.gainAttentionFAB()

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.ui.modules.messages.compose package pl.szczodrzynski.edziennik.ui.modules.messages.compose
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
@ -43,6 +44,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.MessagesConfigDialog
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils.getProfileImage import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils.getProfileImage
import pl.szczodrzynski.edziennik.utils.Colors import pl.szczodrzynski.edziennik.utils.Colors
@ -50,6 +52,7 @@ import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.Themes.getPrimaryTextColor import pl.szczodrzynski.edziennik.utils.Themes.getPrimaryTextColor
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.elevateSurface import pl.szczodrzynski.navlib.elevateSurface
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.text.replace import kotlin.text.replace
@ -67,6 +70,10 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
private val profileConfig by lazy { app.config.forProfile().ui }
private val greetingText
get() = profileConfig.messagesGreetingText ?: "\n\nZ poważaniem\n${app.profile.accountOwnerName}"
private var teachers = mutableListOf<Teacher>() private var teachers = mutableListOf<Teacher>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -131,6 +138,16 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
} }
}*/ }*/
activity.bottomSheet.prependItem(
BottomSheetPrimaryItem(true)
.withTitle(R.string.menu_messages_config)
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
.withOnClickListener {
activity.bottomSheet.close()
MessagesConfigDialog(activity, false, null, null)
}
)
launch { launch {
delay(100) delay(100)
getRecipientList() getRecipientList()
@ -290,7 +307,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
b.recipients.setIllegalCharacterIdentifier { c -> b.recipients.setIllegalCharacterIdentifier { c ->
c.toString().matches("[\\n;:_ ]".toRegex()) c.toString().matches("[\\n;:_ ]".toRegex())
} }
b.recipients.setOnChipRemoveListener { _ -> b.recipients.setOnChipRemoveListener {
b.recipients.setSelection(b.recipients.text.length) b.recipients.setSelection(b.recipients.text.length)
} }
@ -318,14 +335,15 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
fabExtendedText = getString(R.string.messages_compose_send) fabExtendedText = getString(R.string.messages_compose_send)
fabIcon = CommunityMaterial.Icon3.cmd_send_outline fabIcon = CommunityMaterial.Icon3.cmd_send_outline
setFabOnClickListener(View.OnClickListener { setFabOnClickListener {
sendMessage() sendMessage()
}) }
} }
activity.gainAttentionFAB() activity.gainAttentionFAB()
} }
@SuppressLint("SetTextI18n")
private fun updateRecipientList(list: List<Teacher>) { launch { private fun updateRecipientList(list: List<Teacher>) { launch {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
teachers = list.sortedBy { it.fullName }.toMutableList() teachers = list.sortedBy { it.fullName }.toMutableList()
@ -344,11 +362,14 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
val adapter = MessagesComposeSuggestionAdapter(activity, teachers) val adapter = MessagesComposeSuggestionAdapter(activity, teachers)
b.recipients.setAdapter(adapter) b.recipients.setAdapter(adapter)
if (profileConfig.messagesGreetingOnCompose)
b.text.setText(greetingText)
handleReplyMessage() handleReplyMessage()
handleMailToIntent() handleMailToIntent()
}} }}
private fun handleReplyMessage() { launch { private fun handleReplyMessage() = launch {
val replyMessage = arguments?.getString("message") val replyMessage = arguments?.getString("message")
if (replyMessage != null) { if (replyMessage != null) {
val chipList = mutableListOf<ChipInfo>() val chipList = mutableListOf<ChipInfo>()
@ -370,8 +391,10 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
if (arguments?.getString("type") == "reply") { if (arguments?.getString("type") == "reply") {
// add greeting text // add greeting text
span.replace(0, 0, "\n\nZ poważaniem,\n${app.profile.accountName if (profileConfig.messagesGreetingOnReply)
?: app.profile.studentNameLong ?: ""}\n\n\n") span.replace(0, 0, "$greetingText\n\n\n")
else
span.replace(0, 0, "\n\n")
teachers.firstOrNull { it.id == msg.senderId }?.let { teacher -> teachers.firstOrNull { it.id == msg.senderId }?.let { teacher ->
teacher.image = getProfileImage(48, 24, 16, 12, 1, teacher.fullName) teacher.image = getProfileImage(48, 24, 16, 12, 1, teacher.fullName)
@ -379,7 +402,12 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
} }
subject = "Re: ${msg.subject}" subject = "Re: ${msg.subject}"
} else { } else {
span.replace(0, 0, "\n\n") // add greeting text
if (profileConfig.messagesGreetingOnForward)
span.replace(0, 0, "$greetingText\n\n\n")
else
span.replace(0, 0, "\n\n")
subject = "Fwd: ${msg.subject}" subject = "Fwd: ${msg.subject}"
} }
body = MessagesUtils.htmlToSpannable(activity, msg.body body = MessagesUtils.htmlToSpannable(activity, msg.body
@ -401,7 +429,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
else { else {
b.recipients.requestFocus() b.recipients.requestFocus()
} }
}} }
private fun handleMailToIntent() { private fun handleMailToIntent() {
val teacherId = arguments?.getLong("messageRecipientId") val teacherId = arguments?.getLong("messageRecipientId")

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.after import pl.szczodrzynski.edziennik.after
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED
import pl.szczodrzynski.edziennik.ui.dialogs.MessagesConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog
@ -65,6 +66,13 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
GradesConfigDialog(activity, reloadOnDismiss = false) GradesConfigDialog(activity, reloadOnDismiss = false)
}, },
util.createActionItem(
text = R.string.menu_messages_config,
icon = CommunityMaterial.Icon.cmd_calendar_outline
) {
MessagesConfigDialog(activity, reloadOnDismiss = false)
},
util.createActionItem( util.createActionItem(
text = R.string.menu_attendance_config, text = R.string.menu_attendance_config,
icon = CommunityMaterial.Icon.cmd_calendar_remove_outline icon = CommunityMaterial.Icon.cmd_calendar_remove_outline

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) Kuba Szczodrzyński 2021-4-10.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="config"
type="pl.szczodrzynski.edziennik.config.ProfileConfigUI" />
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/messages_config_compose"
android:textAppearance="@style/NavView.TextView.Subtitle" />
<com.google.android.material.checkbox.MaterialCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="@={config.messagesGreetingOnCompose}"
android:minHeight="32dp"
android:text="@string/messages_config_greeting_on_compose" />
<com.google.android.material.checkbox.MaterialCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="@={config.messagesGreetingOnReply}"
android:minHeight="32dp"
android:text="@string/messages_config_greeting_on_reply" />
<com.google.android.material.checkbox.MaterialCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="@={config.messagesGreetingOnForward}"
android:minHeight="32dp"
android:text="@string/messages_config_greeting_on_forward" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/messages_config_greeting_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/greetingText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine|textShortMessage|textAutoCorrect|textAutoComplete"
android:minLines="3"
android:maxLines="10"
tools:text="\n\nZ poważaniem\nJan Kowalski" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</ScrollView>
</layout>

View File

@ -1427,4 +1427,10 @@
<string name="permissions_generate_timetable">Aby móc zapisać wygenerowany plan lekcji musisz przyznać uprawnienia dostępu do pamięci urządzenia.\n\nKliknij OK, aby przyznać uprawnienia.</string> <string name="permissions_generate_timetable">Aby móc zapisać wygenerowany plan lekcji musisz przyznać uprawnienia dostępu do pamięci urządzenia.\n\nKliknij OK, aby przyznać uprawnienia.</string>
<string name="privacy_policy_dialog_html"><![CDATA[Korzystając z aplikacji potwierdzasz <a href="https://szkolny.eu/privacy-policy">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia.<br /><br />Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]></string> <string name="privacy_policy_dialog_html"><![CDATA[Korzystając z aplikacji potwierdzasz <a href="https://szkolny.eu/privacy-policy">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia.<br /><br />Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]></string>
<string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string> <string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string>
<string name="messages_config_compose">Tworzenie wiadomości</string>
<string name="messages_config_greeting_on_compose">Dodaj podpis przy tworzeniu wiadomości</string>
<string name="messages_config_greeting_on_reply">Dodaj podpis przy odpowiadaniu na wiadomość</string>
<string name="messages_config_greeting_on_forward">Dodaj podpis przy przekazywaniu wiadomości</string>
<string name="messages_config_greeting_text">Treść podpisu</string>
<string name="menu_messages_config">Ustawienia wiadomości</string>
</resources> </resources>