Add incognito mode in messages (#1970)

Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
This commit is contained in:
Mateusz Idziejczak 2023-07-26 22:17:58 +02:00 committed by GitHub
parent 91d7ee442e
commit 64cc24ae60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 96 additions and 17 deletions

View File

@ -3,18 +3,26 @@ package io.github.wulkanowy.data.repositories
import android.content.Context import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.* import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.dao.MailboxDao import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.* import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
import io.github.wulkanowy.data.mappers.mapFromEntities import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.onResourceSuccess
import io.github.wulkanowy.data.pojos.MessageDraft import io.github.wulkanowy.data.pojos.MessageDraft
import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.sdk.pojo.Folder
@ -25,7 +33,6 @@ import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import timber.log.Timber import timber.log.Timber
@ -97,7 +104,7 @@ class MessageRepository @Inject constructor(
shouldFetch = { shouldFetch = {
checkNotNull(it) { "This message no longer exist!" } checkNotNull(it) { "This message no longer exist!" }
Timber.d("Message content in db empty: ${it.message.content.isBlank()}") Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
it.message.unread || it.message.content.isBlank() (it.message.unread && markAsRead) || it.message.content.isBlank()
}, },
query = { query = {
messagesDb.loadMessageWithAttachment(message.messageGlobalKey) messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
@ -113,7 +120,10 @@ class MessageRepository @Inject constructor(
messagesDb.updateAll( messagesDb.updateAll(
listOf(old.message.apply { listOf(old.message.apply {
id = message.id id = message.id
unread = !markAsRead unread = when {
markAsRead -> false
else -> unread
}
sender = new.sender sender = new.sender
recipients = new.recipients.singleOrNull() ?: "Wielu adresatów" recipients = new.recipients.singleOrNull() ?: "Wielu adresatów"
content = content.ifBlank { new.content } content = content.ifBlank { new.content }
@ -123,7 +133,7 @@ class MessageRepository @Inject constructor(
items = new.attachments.mapToEntities(message.messageGlobalKey), items = new.attachments.mapToEntities(message.messageGlobalKey),
) )
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read") Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read: $markAsRead")
} }
) )

View File

@ -343,6 +343,12 @@ class PreferencesRepository @Inject constructor(
) )
} }
var isIncognitoMode: Boolean
get() = getBoolean(R.string.pref_key_incognito_moge, R.bool.pref_default_incognito_mode)
set(value) = sharedPref.edit {
putBoolean(context.getString(R.string.pref_key_incognito_moge), value)
}
var installationId: String var installationId: String
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty() get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) } private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }

View File

@ -11,7 +11,9 @@ import androidx.core.view.updateMargins
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.MessageFolder.* import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.enums.MessageFolder.SENT
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
import io.github.wulkanowy.databinding.FragmentMessageBinding import io.github.wulkanowy.databinding.FragmentMessageBinding
import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
@ -49,6 +51,7 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding = FragmentMessageBinding.bind(view) binding = FragmentMessageBinding.bind(view)
messageContainer = binding.messageViewPager
presenter.onAttachView(this) presenter.onAttachView(this)
} }
@ -95,6 +98,10 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
binding.messageProgress.visibility = if (show) VISIBLE else INVISIBLE binding.messageProgress.visibility = if (show) VISIBLE else INVISIBLE
} }
override fun showMessage(messageId: Int) {
showMessage(getString(messageId))
}
override fun showNewMessage(show: Boolean) { override fun showNewMessage(show: Boolean) {
binding.openSendMessageButton.run { binding.openSendMessageButton.run {
if (show) show() else hide() if (show) show() else hide()

View File

@ -1,5 +1,7 @@
package io.github.wulkanowy.ui.modules.message package io.github.wulkanowy.ui.modules.message
import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
@ -9,7 +11,8 @@ import javax.inject.Inject
class MessagePresenter @Inject constructor( class MessagePresenter @Inject constructor(
errorHandler: ErrorHandler, errorHandler: ErrorHandler,
studentRepository: StudentRepository studentRepository: StudentRepository,
private val preferencesRepository: PreferencesRepository,
) : BasePresenter<MessageView>(errorHandler, studentRepository) { ) : BasePresenter<MessageView>(errorHandler, studentRepository) {
override fun onAttachView(view: MessageView) { override fun onAttachView(view: MessageView) {
@ -19,6 +22,14 @@ class MessagePresenter @Inject constructor(
Timber.i("Message view was initialized") Timber.i("Message view was initialized")
loadData() loadData()
} }
showIncognitoModeReminderMessage()
}
private fun showIncognitoModeReminderMessage() {
if (preferencesRepository.isIncognitoMode) {
view?.showMessage(R.string.message_incognito_mode_on)
}
} }
fun onPageSelected(index: Int) { fun onPageSelected(index: Int) {

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message package io.github.wulkanowy.ui.modules.message
import androidx.annotation.StringRes
import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.base.BaseView
interface MessageView : BaseView { interface MessageView : BaseView {
@ -12,6 +13,8 @@ interface MessageView : BaseView {
fun showProgress(show: Boolean) fun showProgress(show: Boolean)
fun showMessage(@StringRes messageId: Int)
fun showNewMessage(show: Boolean) fun showNewMessage(show: Boolean)
fun showTabLayout(show: Boolean) fun showTabLayout(show: Boolean)

View File

@ -12,6 +12,7 @@ import android.view.View.VISIBLE
import android.webkit.WebResourceRequest import android.webkit.WebResourceRequest
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import androidx.annotation.StringRes
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -164,6 +165,10 @@ class MessagePreviewFragment :
binding.messagePreviewErrorRetry.setOnClickListener { callback() } binding.messagePreviewErrorRetry.setOnClickListener { callback() }
} }
override fun showMessage(@StringRes messageId: Int) {
showMessage(getString(messageId))
}
override fun openMessageReply(message: Message?) { override fun openMessageReply(message: Message?) {
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message, true)) } context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message, true)) }
} }

View File

@ -2,11 +2,13 @@ package io.github.wulkanowy.ui.modules.message.preview
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.core.text.parseAsHtml import androidx.core.text.parseAsHtml
import io.github.wulkanowy.R
import io.github.wulkanowy.data.* import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.enums.MessageFolder import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.repositories.MessageRepository import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
@ -20,6 +22,7 @@ class MessagePreviewPresenter @Inject constructor(
errorHandler: ErrorHandler, errorHandler: ErrorHandler,
studentRepository: StudentRepository, studentRepository: StudentRepository,
private val messageRepository: MessageRepository, private val messageRepository: MessageRepository,
private val preferencesRepository: PreferencesRepository,
private val analytics: AnalyticsHelper private val analytics: AnalyticsHelper
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) { ) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
@ -54,7 +57,11 @@ class MessagePreviewPresenter @Inject constructor(
private fun loadData(messageToLoad: Message) { private fun loadData(messageToLoad: Message) {
flatResourceFlow { flatResourceFlow {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
messageRepository.getMessage(student, messageToLoad, true) messageRepository.getMessage(
student = student,
message = messageToLoad,
markAsRead = !preferencesRepository.isIncognitoMode,
)
} }
.logResourceStatus("message ${messageToLoad.messageId} preview") .logResourceStatus("message ${messageToLoad.messageId} preview")
.onResourceData { .onResourceData {
@ -65,6 +72,10 @@ class MessagePreviewPresenter @Inject constructor(
setMessageWithAttachment(it) setMessageWithAttachment(it)
showContent(true) showContent(true)
initOptions() initOptions()
if (preferencesRepository.isIncognitoMode && it.message.unread) {
showMessage(R.string.message_incognito_description)
}
} }
} else { } else {
view?.run { view?.run {

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message.preview package io.github.wulkanowy.ui.modules.message.preview
import androidx.annotation.StringRes
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.base.BaseView
@ -43,4 +44,6 @@ interface MessagePreviewView : BaseView {
fun popView() fun popView()
fun printDocument(html: String, jobName: String) fun printDocument(html: String, jobName: String)
fun showMessage(@StringRes messageId: Int)
} }

View File

@ -7,6 +7,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.View.* import android.view.View.*
import android.widget.CompoundButton import android.widget.CompoundButton
import androidx.annotation.StringRes
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
@ -134,14 +135,20 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
} }
} }
@Deprecated("Deprecated in Java")
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.action_menu_message_tab, menu) inflater.inflate(R.menu.action_menu_message_tab, menu)
val searchView = menu.findItem(R.id.action_search).actionView as SearchView initializeSearchView(menu)
searchView.queryHint = getString(R.string.all_search_hint) }
searchView.maxWidth = Int.MAX_VALUE
private fun initializeSearchView(menu: Menu) {
val searchView = (menu.findItem(R.id.action_search).actionView as SearchView).apply {
queryHint = getString(R.string.all_search_hint)
maxWidth = Int.MAX_VALUE
}
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String) = false override fun onQueryTextSubmit(query: String) = false
override fun onQueryTextChange(query: String): Boolean { override fun onQueryTextChange(query: String): Boolean {
@ -207,8 +214,8 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
binding.messageTabSwipe.isRefreshing = show binding.messageTabSwipe.isRefreshing = show
} }
override fun showMessagesDeleted() { override fun showMessage(@StringRes messageId: Int) {
showMessage(getString(R.string.message_messages_deleted)) showMessage(getString(messageId))
} }
override fun notifyParentShowNewMessage(show: Boolean) { override fun notifyParentShowNewMessage(show: Boolean) {

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message.tab package io.github.wulkanowy.ui.modules.message.tab
import io.github.wulkanowy.R
import io.github.wulkanowy.data.* import io.github.wulkanowy.data.*
import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
@ -26,7 +27,7 @@ class MessageTabPresenter @Inject constructor(
errorHandler: ErrorHandler, errorHandler: ErrorHandler,
studentRepository: StudentRepository, studentRepository: StudentRepository,
private val messageRepository: MessageRepository, private val messageRepository: MessageRepository,
private val analytics: AnalyticsHelper private val analytics: AnalyticsHelper,
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) { ) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
lateinit var folder: MessageFolder lateinit var folder: MessageFolder
@ -135,7 +136,7 @@ class MessageTabPresenter @Inject constructor(
messageRepository.deleteMessages(student, selectedMailbox, messageList) messageRepository.deleteMessages(student, selectedMailbox, messageList)
} }
.onFailure(errorHandler::dispatch) .onFailure(errorHandler::dispatch)
.onSuccess { view?.showMessagesDeleted() } .onSuccess { view?.showMessage(R.string.message_messages_deleted) }
} }
} }

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message.tab package io.github.wulkanowy.ui.modules.message.tab
import androidx.annotation.StringRes
import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.base.BaseView
@ -26,7 +27,7 @@ interface MessageTabView : BaseView {
fun showEmpty(show: Boolean) fun showEmpty(show: Boolean)
fun showMessagesDeleted() fun showMessage(@StringRes messageId: Int)
fun showErrorView(show: Boolean) fun showErrorView(show: Boolean)

View File

@ -38,4 +38,5 @@
</string-array> </string-array>
<bool name="pref_default_ads_enabled">false</bool> <bool name="pref_default_ads_enabled">false</bool>
<bool name="pref_default_ads_consent_data_processing">false</bool> <bool name="pref_default_ads_consent_data_processing">false</bool>
<bool name="pref_default_incognito_mode">false</bool>
</resources> </resources>

View File

@ -39,5 +39,6 @@
<string name="pref_key_ads_privacy_policy">ads_privacy_policy</string> <string name="pref_key_ads_privacy_policy">ads_privacy_policy</string>
<string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string> <string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string>
<string name="pref_key_ads_over_eighteen">ads_over_eighteen</string> <string name="pref_key_ads_over_eighteen">ads_over_eighteen</string>
<string name="pref_key_incognito_moge">incognito_mode</string>
<string name="pref_key_menu_order">appearance_menu_order</string> <string name="pref_key_menu_order">appearance_menu_order</string>
</resources> </resources>

View File

@ -339,6 +339,8 @@
</plurals> </plurals>
<string name="message_messages_deleted">Messages deleted</string> <string name="message_messages_deleted">Messages deleted</string>
<string name="message_mailbox_chooser_title">Choose mailbox</string> <string name="message_mailbox_chooser_title">Choose mailbox</string>
<string name="message_incognito_mode_on">Incognito mode is on</string>
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
<!--Note--> <!--Note-->
@ -728,6 +730,9 @@
<string name="pref_other_grade_modifier_minus">Value of the minus</string> <string name="pref_other_grade_modifier_minus">Value of the minus</string>
<string name="pref_other_fill_message_content">Reply with message history</string> <string name="pref_other_fill_message_content">Reply with message history</string>
<string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string> <string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string>
<string name="pref_other_incognito_mode">Incognito mode</string>
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
<string name="pref_ads_support_category_name">Support</string> <string name="pref_ads_support_category_name">Support</string>
<string name="pref_ads_privacy_policy">Privacy Policy</string> <string name="pref_ads_privacy_policy">Privacy Policy</string>
<string name="pref_ads_agreements">Agreements</string> <string name="pref_ads_agreements">Agreements</string>

View File

@ -53,5 +53,12 @@
app:key="@string/pref_key_fill_message_content" app:key="@string/pref_key_fill_message_content"
app:singleLineTitle="false" app:singleLineTitle="false"
app:title="@string/pref_other_fill_message_content" /> app:title="@string/pref_other_fill_message_content" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_incognito_mode"
app:iconSpaceReserved="false"
app:key="@string/pref_key_incognito_moge"
app:singleLineTitle="false"
app:title="@string/pref_other_incognito_mode"
app:summary="@string/pref_other_incognito_mode_summary" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>