From 11167aff5b90d5ef51561f82c05faa35777a2100 Mon Sep 17 00:00:00 2001 From: Moez Bhatti Date: Wed, 9 May 2018 15:20:58 -0400 Subject: [PATCH] Remove SetupActivity, perform setup in MainActivity Squashed commit of the following: commit ff6ece72a60917ceec3ea1485901e8929e65bb43 Author: Moez Bhatti Date: Wed May 9 01:50:33 2018 -0400 Remove default SMS UI from settings commit 1ce79ea756259268c4d2fcd8acbee3101fdbe019 Author: Moez Bhatti Date: Wed May 9 01:45:33 2018 -0400 Remove SetupActivity, perform setup in MainActivity commit ccad342d2ab8a5346d63dab273ba9cadb2fa62c0 Author: Moez Bhatti Date: Mon May 7 18:02:26 2018 -0400 Don't query ContentProvider without appropriate permission commit 527be2e5331ba0cbfd6f3375c12378105d282b0c Author: Moez Bhatti Date: Mon May 7 17:12:00 2018 -0400 Show non-blocking UI in MainActivity while syncing --- .../java/manager/PermissionManagerImpl.kt | 13 +- .../main/java/mapper/CursorToContactImpl.kt | 11 +- .../java/mapper/CursorToConversationImpl.kt | 16 +- .../main/java/mapper/CursorToMessageImpl.kt | 9 +- .../main/java/mapper/CursorToRecipientImpl.kt | 11 +- .../java/repository/SyncRepositoryImpl.kt | 82 +++----- data/src/main/java/util/Preferences.kt | 1 - .../src/main/java/interactor/PartialSync.kt | 42 ---- .../{FullSync.kt => SyncMessages.kt} | 4 +- .../main/java/manager/PermissionManager.kt | 6 + .../main/java/repository/SyncRepository.kt | 10 +- presentation/src/main/AndroidManifest.xml | 1 - .../src/main/java/common/Navigator.kt | 8 - .../main/java/feature/main/MainActivity.kt | 40 +++- .../src/main/java/feature/main/MainState.kt | 8 +- .../src/main/java/feature/main/MainView.kt | 3 + .../main/java/feature/main/MainViewModel.kt | 90 +++++--- .../java/feature/settings/SettingsActivity.kt | 5 - .../java/feature/settings/SettingsState.kt | 1 - .../feature/settings/SettingsViewModel.kt | 16 +- .../main/java/feature/setup/SetupActivity.kt | 75 ------- .../src/main/java/feature/setup/SetupState.kt | 21 -- .../src/main/java/feature/setup/SetupView.kt | 35 ---- .../main/java/feature/setup/SetupViewModel.kt | 62 ------ .../src/main/java/injection/AppComponent.kt | 4 - .../receiver/DefaultSmsChangedReceiver.kt | 11 +- .../src/main/res/layout/main_activity.xml | 195 +++++++++++------- .../src/main/res/layout/settings_activity.xml | 12 -- .../src/main/res/layout/setup_activity.xml | 88 -------- .../src/main/res/values-bn/strings.xml | 4 +- .../src/main/res/values-cs/strings.xml | 4 +- .../src/main/res/values-da/strings.xml | 4 +- .../src/main/res/values-de/strings.xml | 4 +- .../src/main/res/values-es/strings.xml | 4 +- .../src/main/res/values-fa/strings.xml | 4 +- .../src/main/res/values-fi/strings.xml | 4 +- .../src/main/res/values-fr/strings.xml | 4 +- .../src/main/res/values-hi/strings.xml | 4 +- .../src/main/res/values-hr/strings.xml | 4 +- .../src/main/res/values-hu/strings.xml | 4 +- .../src/main/res/values-in/strings.xml | 4 +- .../src/main/res/values-it/strings.xml | 4 +- .../src/main/res/values-iw/strings.xml | 4 +- .../src/main/res/values-ja/strings.xml | 4 +- .../src/main/res/values-ko/strings.xml | 4 +- .../src/main/res/values-lt/strings.xml | 4 +- .../src/main/res/values-ne/strings.xml | 4 +- .../src/main/res/values-nl/strings.xml | 4 +- .../src/main/res/values-no/strings.xml | 4 +- .../src/main/res/values-pl/strings.xml | 4 +- .../src/main/res/values-pt-rBR/strings.xml | 4 +- .../src/main/res/values-pt/strings.xml | 4 +- .../src/main/res/values-ro/strings.xml | 4 +- .../src/main/res/values-ru/strings.xml | 4 +- .../src/main/res/values-sk/strings.xml | 4 +- .../src/main/res/values-sr/strings.xml | 4 +- .../src/main/res/values-sv/strings.xml | 4 +- .../src/main/res/values-tl/strings.xml | 4 +- .../src/main/res/values-tr/strings.xml | 4 +- .../src/main/res/values-vi/strings.xml | 4 +- .../src/main/res/values-zh-rCN/strings.xml | 4 +- .../src/main/res/values-zh/strings.xml | 4 +- presentation/src/main/res/values/strings.xml | 14 +- 63 files changed, 408 insertions(+), 618 deletions(-) delete mode 100644 domain/src/main/java/interactor/PartialSync.kt rename domain/src/main/java/interactor/{FullSync.kt => SyncMessages.kt} (93%) delete mode 100644 presentation/src/main/java/feature/setup/SetupActivity.kt delete mode 100644 presentation/src/main/java/feature/setup/SetupState.kt delete mode 100644 presentation/src/main/java/feature/setup/SetupView.kt delete mode 100644 presentation/src/main/java/feature/setup/SetupViewModel.kt delete mode 100644 presentation/src/main/res/layout/setup_activity.xml diff --git a/data/src/main/java/manager/PermissionManagerImpl.kt b/data/src/main/java/manager/PermissionManagerImpl.kt index bb5453bb7..3b7f1d2df 100644 --- a/data/src/main/java/manager/PermissionManagerImpl.kt +++ b/data/src/main/java/manager/PermissionManagerImpl.kt @@ -21,14 +21,23 @@ package manager import android.Manifest import android.content.Context import android.content.pm.PackageManager +import android.provider.Telephony import android.support.v4.content.ContextCompat import javax.inject.Inject class PermissionManagerImpl @Inject constructor(private val context: Context) : PermissionManager { + override fun isDefaultSms(): Boolean { + return Telephony.Sms.getDefaultSmsPackage(context) == context.packageName + } + override fun hasSmsAndContacts(): Boolean { - return ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED && - ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED + return hasSms() && hasContacts() } + override fun hasSms(): Boolean = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED + + override fun hasContacts(): Boolean = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED + + } \ No newline at end of file diff --git a/data/src/main/java/mapper/CursorToContactImpl.kt b/data/src/main/java/mapper/CursorToContactImpl.kt index e78254cc9..bcb3e070a 100644 --- a/data/src/main/java/mapper/CursorToContactImpl.kt +++ b/data/src/main/java/mapper/CursorToContactImpl.kt @@ -21,11 +21,15 @@ package mapper import android.content.Context import android.database.Cursor import android.provider.ContactsContract.CommonDataKinds.Phone.* +import manager.PermissionManager import model.Contact import model.PhoneNumber import javax.inject.Inject -class CursorToContactImpl @Inject constructor(private val context: Context) : CursorToContact { +class CursorToContactImpl @Inject constructor( + private val context: Context, + private val permissionManager: PermissionManager +) : CursorToContact { companion object { val URI = CONTENT_URI @@ -48,7 +52,10 @@ class CursorToContactImpl @Inject constructor(private val context: Context) : Cu } override fun getContactsCursor(): Cursor? { - return context.contentResolver.query(URI, PROJECTION, null, null, null) + return when (permissionManager.hasContacts()) { + true -> context.contentResolver.query(URI, PROJECTION, null, null, null) + false -> null + } } } \ No newline at end of file diff --git a/data/src/main/java/mapper/CursorToConversationImpl.kt b/data/src/main/java/mapper/CursorToConversationImpl.kt index 8e40873b0..925e2eaf5 100644 --- a/data/src/main/java/mapper/CursorToConversationImpl.kt +++ b/data/src/main/java/mapper/CursorToConversationImpl.kt @@ -22,11 +22,15 @@ import android.content.Context import android.database.Cursor import android.net.Uri import android.provider.Telephony.Threads +import manager.PermissionManager import model.Conversation import model.Recipient import javax.inject.Inject -class CursorToConversationImpl @Inject constructor(private val context: Context) : CursorToConversation { +class CursorToConversationImpl @Inject constructor( + private val context: Context, + private val permissionManager: PermissionManager +) : CursorToConversation { companion object { val URI: Uri = Uri.parse("content://mms-sms/conversations?simple=true") @@ -62,9 +66,13 @@ class CursorToConversationImpl @Inject constructor(private val context: Context) } override fun getConversationsCursor(lastSync: Long): Cursor? { - return context.contentResolver.query(URI, PROJECTION, - "date > $lastSync", null, - "date desc") + return when (permissionManager.hasSms()) { + true -> context.contentResolver.query(URI, PROJECTION, + "date > $lastSync", null, + "date desc") + + false -> null + } } override fun getConversationCursor(threadId: Long): Cursor? { diff --git a/data/src/main/java/mapper/CursorToMessageImpl.kt b/data/src/main/java/mapper/CursorToMessageImpl.kt index 436a9bac2..ddb1e268b 100644 --- a/data/src/main/java/mapper/CursorToMessageImpl.kt +++ b/data/src/main/java/mapper/CursorToMessageImpl.kt @@ -24,14 +24,16 @@ import android.net.Uri import android.provider.Telephony.* import com.google.android.mms.pdu_alt.PduHeaders import manager.KeyManager +import manager.PermissionManager import model.Message import util.extensions.map import javax.inject.Inject class CursorToMessageImpl @Inject constructor( private val context: Context, + private val cursorToPart: CursorToPart, private val keys: KeyManager, - private val cursorToPart: CursorToPart + private val permissionManager: PermissionManager ) : CursorToMessage { companion object { @@ -120,7 +122,10 @@ class CursorToMessageImpl @Inject constructor( } override fun getMessagesCursor(): Cursor? { - return context.contentResolver.query(URI, PROJECTION, null, null, "normalized_date desc") + return when (permissionManager.hasSms()) { + true -> context.contentResolver.query(URI, PROJECTION, null, null, "normalized_date desc") + false -> null + } } override fun getMessageCursor(id: Long): Cursor? { diff --git a/data/src/main/java/mapper/CursorToRecipientImpl.kt b/data/src/main/java/mapper/CursorToRecipientImpl.kt index 08b6258a3..ff89e07f5 100644 --- a/data/src/main/java/mapper/CursorToRecipientImpl.kt +++ b/data/src/main/java/mapper/CursorToRecipientImpl.kt @@ -21,10 +21,14 @@ package mapper import android.content.Context import android.database.Cursor import android.net.Uri +import manager.PermissionManager import model.Recipient import javax.inject.Inject -class CursorToRecipientImpl @Inject constructor(private val context: Context) : CursorToRecipient { +class CursorToRecipientImpl @Inject constructor( + private val context: Context, + private val permissionManager: PermissionManager +) : CursorToRecipient { companion object { val URI = Uri.parse("content://mms-sms/canonical-addresses") @@ -40,7 +44,10 @@ class CursorToRecipientImpl @Inject constructor(private val context: Context) : } override fun getRecipientCursor(): Cursor? { - return context.contentResolver.query(URI, null, null, null, null) + return when (permissionManager.hasSms()) { + true -> context.contentResolver.query(URI, null, null, null, null) + false -> null + } } override fun getRecipientCursor(id: Long): Cursor? { diff --git a/data/src/main/java/repository/SyncRepositoryImpl.kt b/data/src/main/java/repository/SyncRepositoryImpl.kt index d08e4b3ef..519692f0a 100644 --- a/data/src/main/java/repository/SyncRepositoryImpl.kt +++ b/data/src/main/java/repository/SyncRepositoryImpl.kt @@ -24,6 +24,8 @@ import android.net.Uri import android.provider.Telephony import android.telephony.PhoneNumberUtils import com.f2prateek.rx.preferences2.RxSharedPreferences +import io.reactivex.subjects.BehaviorSubject +import io.reactivex.subjects.Subject import io.realm.Realm import mapper.CursorToContact import mapper.CursorToConversation @@ -34,10 +36,8 @@ import model.Conversation import model.Message import model.MmsPart import model.Recipient -import model.SyncLog import util.extensions.insertOrUpdate import util.extensions.map -import util.extensions.mapWhile import util.tryOrNull import javax.inject.Inject import javax.inject.Singleton @@ -53,58 +53,41 @@ class SyncRepositoryImpl @Inject constructor( private val rxPrefs: RxSharedPreferences ) : SyncRepository { - sealed class Status { - class Idle : Status() - class Running : Status() - } - /** * Holds data that should be persisted across full syncs */ private data class PersistedData(val id: Long, val archived: Boolean, val blocked: Boolean) - private var status: Status = Status.Idle() + override val syncProgress: Subject = BehaviorSubject.createDefault(SyncRepository.SyncProgress.Idle()) - override fun syncMessages(fullSync: Boolean) { + override fun syncMessages() { // If the sync is already running, don't try to do another one - if (status is Status.Running) return - status = Status.Running() + if (syncProgress.blockingFirst() is SyncRepository.SyncProgress.Running) return + syncProgress.onNext(SyncRepository.SyncProgress.Running(0f)) val realm = Realm.getDefaultInstance() realm.beginTransaction() - var persistedData: List = listOf() - - if (fullSync) { - persistedData += realm.where(Conversation::class.java) - .beginGroup() - .equalTo("archived", true) - .or() - .equalTo("blocked", true) - .endGroup() - .findAll() - .map { conversation -> - PersistedData(conversation.id, conversation.archived, conversation.blocked) - } - - realm.delete(Conversation::class.java) - realm.delete(Message::class.java) - realm.delete(MmsPart::class.java) - realm.delete(Recipient::class.java) - realm.delete(SyncLog::class.java) - } + var persistedData = realm.where(Conversation::class.java) + .beginGroup() + .equalTo("archived", true) + .or() + .equalTo("blocked", true) + .endGroup() + .findAll() + .map { PersistedData(it.id, it.archived, it.blocked) } - val lastSync = realm.where(SyncLog::class.java)?.max("date")?.toLong() ?: 0 - realm.insert(SyncLog()) + realm.delete(Conversation::class.java) + realm.delete(Message::class.java) + realm.delete(MmsPart::class.java) + realm.delete(Recipient::class.java) // Sync messages cursorToMessage.getMessagesCursor()?.use { messageCursor -> val messageColumns = CursorToMessage.MessageColumns(messageCursor) - val messages = messageCursor.mapWhile( - { cursor -> cursorToMessage.map(Pair(cursor, messageColumns)) }, - { message -> message.date > lastSync }) + val messages = messageCursor.map { cursor -> cursorToMessage.map(Pair(cursor, messageColumns)) } realm.insertOrUpdate(messages) } @@ -144,7 +127,7 @@ class SyncRepositoryImpl @Inject constructor( syncContacts() - status = Status.Idle() + syncProgress.onNext(SyncRepository.SyncProgress.Idle()) } override fun syncMessage(uri: Uri): Message? { @@ -204,26 +187,27 @@ class SyncRepositoryImpl @Inject constructor( } } ?: listOf() - val realm = Realm.getDefaultInstance() - val recipients = realm.where(Recipient::class.java).findAll() + Realm.getDefaultInstance()?.use { realm -> + val recipients = realm.where(Recipient::class.java).findAll() - realm.executeTransaction { - realm.delete(Contact::class.java) + realm.executeTransaction { + realm.delete(Contact::class.java) - contacts = realm.copyToRealm(contacts) + contacts = realm.copyToRealm(contacts) - // Update all the recipients with the new contacts - val updatedRecipients = recipients.map { recipient -> - recipient.apply { - contact = contacts.firstOrNull { - it.numbers.any { PhoneNumberUtils.compare(recipient.address, it.address) } + // Update all the recipients with the new contacts + val updatedRecipients = recipients.map { recipient -> + recipient.apply { + contact = contacts.firstOrNull { + it.numbers.any { PhoneNumberUtils.compare(recipient.address, it.address) } + } } } + + realm.insertOrUpdate(updatedRecipients) } - realm.insertOrUpdate(updatedRecipients) } - realm.close() } } \ No newline at end of file diff --git a/data/src/main/java/util/Preferences.kt b/data/src/main/java/util/Preferences.kt index 0e8dd443b..6bf3628f8 100644 --- a/data/src/main/java/util/Preferences.kt +++ b/data/src/main/java/util/Preferences.kt @@ -48,7 +48,6 @@ class Preferences @Inject constructor(private val rxPrefs: RxSharedPreferences) const val SEND_DELAY_LONG = 3 } - val defaultSms = rxPrefs.getBoolean("defaultSms", false) val night = rxPrefs.getBoolean("night", false) val nightMode = rxPrefs.getInteger("nightModeSummary", NIGHT_MODE_OFF) val nightStart = rxPrefs.getString("nightStart", "6:00 PM") diff --git a/domain/src/main/java/interactor/PartialSync.kt b/domain/src/main/java/interactor/PartialSync.kt deleted file mode 100644 index e764f924e..000000000 --- a/domain/src/main/java/interactor/PartialSync.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package interactor - -import io.reactivex.Flowable -import manager.PermissionManager -import repository.SyncRepository -import timber.log.Timber -import java.util.concurrent.TimeUnit -import javax.inject.Inject - -open class PartialSync @Inject constructor( - private val syncManager: SyncRepository, - private val permissions: PermissionManager -) : Interactor() { - - override fun buildObservable(params: Unit): Flowable { - return Flowable.just(System.currentTimeMillis()) - .skipWhile { !permissions.hasSmsAndContacts() } - .doOnNext { syncManager.syncMessages() } - .map { startTime -> System.currentTimeMillis() - startTime } - .map { elapsed -> TimeUnit.MILLISECONDS.toSeconds(elapsed) } - .doOnNext { seconds -> Timber.v("Completed sync in $seconds seconds") } - } - -} \ No newline at end of file diff --git a/domain/src/main/java/interactor/FullSync.kt b/domain/src/main/java/interactor/SyncMessages.kt similarity index 93% rename from domain/src/main/java/interactor/FullSync.kt rename to domain/src/main/java/interactor/SyncMessages.kt index a71d84a10..40e8c87ad 100644 --- a/domain/src/main/java/interactor/FullSync.kt +++ b/domain/src/main/java/interactor/SyncMessages.kt @@ -25,7 +25,7 @@ import timber.log.Timber import java.util.concurrent.TimeUnit import javax.inject.Inject -class FullSync @Inject constructor( +class SyncMessages @Inject constructor( private val syncManager: SyncRepository, private val keys: KeyManager ) : Interactor() { @@ -33,7 +33,7 @@ class FullSync @Inject constructor( override fun buildObservable(params: Unit): Flowable { return Flowable.just(System.currentTimeMillis()) .doOnNext { keys.reset() } - .doOnNext { syncManager.syncMessages(true) } + .doOnNext { syncManager.syncMessages() } .map { startTime -> System.currentTimeMillis() - startTime } .map { elapsed -> TimeUnit.MILLISECONDS.toSeconds(elapsed) } .doOnNext { seconds -> Timber.v("Completed sync in $seconds seconds") } diff --git a/domain/src/main/java/manager/PermissionManager.kt b/domain/src/main/java/manager/PermissionManager.kt index 675fba3c9..eb25c54e7 100644 --- a/domain/src/main/java/manager/PermissionManager.kt +++ b/domain/src/main/java/manager/PermissionManager.kt @@ -20,6 +20,12 @@ package manager interface PermissionManager { + fun isDefaultSms(): Boolean + fun hasSmsAndContacts(): Boolean + fun hasSms(): Boolean + + fun hasContacts(): Boolean + } \ No newline at end of file diff --git a/domain/src/main/java/repository/SyncRepository.kt b/domain/src/main/java/repository/SyncRepository.kt index 17932408f..16d5e484b 100644 --- a/domain/src/main/java/repository/SyncRepository.kt +++ b/domain/src/main/java/repository/SyncRepository.kt @@ -19,11 +19,19 @@ package repository import android.net.Uri +import io.reactivex.Observable import model.Message interface SyncRepository { - fun syncMessages(fullSync: Boolean = false) + sealed class SyncProgress { + class Idle : SyncProgress() + class Running(progress: Float) : SyncProgress() + } + + val syncProgress: Observable + + fun syncMessages() fun syncMessage(uri: Uri): Message? diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index e52e2621c..df3465fdd 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -58,7 +58,6 @@ - MainViewModel() PlusViewModel::class.java -> PlusViewModel() - SetupViewModel::class.java -> SetupViewModel() AboutViewModel::class.java -> AboutViewModel() ComposeViewModel::class.java -> ComposeViewModel(intent) ConversationInfoViewModel::class.java -> ConversationInfoViewModel(intent) diff --git a/presentation/src/main/java/feature/main/MainActivity.kt b/presentation/src/main/java/feature/main/MainActivity.kt index 9d60a2b69..b864433f0 100644 --- a/presentation/src/main/java/feature/main/MainActivity.kt +++ b/presentation/src/main/java/feature/main/MainActivity.kt @@ -18,12 +18,14 @@ */ package feature.main +import android.Manifest import android.app.AlertDialog import android.content.res.ColorStateList import android.graphics.drawable.ColorDrawable import android.graphics.drawable.StateListDrawable import android.os.Bundle import android.support.design.widget.Snackbar +import android.support.v4.app.ActivityCompat import android.support.v7.app.ActionBarDrawerToggle import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.helper.ItemTouchHelper @@ -53,6 +55,7 @@ import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.Subject import kotlinx.android.synthetic.main.drawer_view.* import kotlinx.android.synthetic.main.main_activity.* +import repository.SyncRepository import javax.inject.Inject class MainActivity : QkThemedActivity(), MainView { @@ -62,6 +65,7 @@ class MainActivity : QkThemedActivity(), MainView { @Inject lateinit var itemTouchCallback: ConversationItemTouchCallback override val viewModelClass = MainViewModel::class + override val activityResumedIntent: Subject = PublishSubject.create() override val queryChangedIntent by lazy { toolbarSearch.textChanges() } override val composeIntent by lazy { compose.clicks() } override val drawerOpenIntent: Observable by lazy { @@ -86,6 +90,7 @@ class MainActivity : QkThemedActivity(), MainView { override val confirmDeleteIntent: Subject = PublishSubject.create() override val swipeConversationIntent by lazy { itemTouchCallback.swipes } override val undoSwipeConversationIntent: Subject = PublishSubject.create() + override val snackbarButtonIntent by lazy { snackbarButton.clicks() } override val backPressedIntent: Subject = PublishSubject.create() private val toggle by lazy { ActionBarDrawerToggle(this, drawerLayout, toolbar, 0, 0) } @@ -205,8 +210,6 @@ class MainActivity : QkThemedActivity(), MainView { toolbar.menu.findItem(R.id.block)?.isVisible = selectedConversations != 0 toolbar.menu.findItem(R.id.delete)?.isVisible = selectedConversations != 0 - syncing.setVisible(state.syncing) - synced.setVisible(!state.syncing) rateLayout.setVisible(state.showRating) compose.setVisible(state.page is Inbox || state.page is Archived) @@ -255,12 +258,45 @@ class MainActivity : QkThemedActivity(), MainView { if (drawerLayout.isDrawerOpen(Gravity.START) && !state.drawerOpen) drawerLayout.closeDrawer(Gravity.START) else if (!drawerLayout.isDrawerVisible(Gravity.START) && state.drawerOpen) drawerLayout.openDrawer(Gravity.START) + + syncing.setVisible(state.syncing is SyncRepository.SyncProgress.Running) + snackbar.setVisible(state.syncing is SyncRepository.SyncProgress.Idle + && !state.defaultSms || !state.smsPermission || !state.contactPermission) + + when { + !state.smsPermission -> { + snackbarTitle.setText(R.string.main_permission_required) + snackbarMessage.setText(R.string.main_permission_sms) + snackbarButton.setText(R.string.main_permission_allow) + } + + !state.defaultSms -> { + snackbarTitle.setText(R.string.main_default_sms_title) + snackbarMessage.setText(R.string.main_default_sms_message) + snackbarButton.setText(R.string.main_default_sms_change) + } + + !state.contactPermission -> { + snackbarTitle.setText(R.string.main_permission_required) + snackbarMessage.setText(R.string.main_permission_contacts) + snackbarButton.setText(R.string.main_permission_allow) + } + } + } + + override fun onResume() { + super.onResume() + activityResumedIntent.onNext(Unit) } override fun showBackButton(show: Boolean) { toggle.onDrawerSlide(drawer, if (show) 1f else 0f) } + override fun requestPermissions() { + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS), 0) + } + override fun clearSearch() { dismissKeyboard() toolbarSearch.text = null diff --git a/presentation/src/main/java/feature/main/MainState.kt b/presentation/src/main/java/feature/main/MainState.kt index fc8a755ee..36462be64 100644 --- a/presentation/src/main/java/feature/main/MainState.kt +++ b/presentation/src/main/java/feature/main/MainState.kt @@ -20,13 +20,17 @@ package feature.main import io.reactivex.Flowable import model.Conversation +import repository.SyncRepository data class MainState( val hasError: Boolean = false, val page: MainPage = Inbox(), val drawerOpen: Boolean = false, - val syncing: Boolean = false, - val showRating: Boolean = false + val showRating: Boolean = false, + val syncing: SyncRepository.SyncProgress = SyncRepository.SyncProgress.Idle(), + val defaultSms: Boolean = false, + val smsPermission: Boolean = false, + val contactPermission: Boolean = false ) sealed class MainPage diff --git a/presentation/src/main/java/feature/main/MainView.kt b/presentation/src/main/java/feature/main/MainView.kt index 957c055fd..63db3e579 100644 --- a/presentation/src/main/java/feature/main/MainView.kt +++ b/presentation/src/main/java/feature/main/MainView.kt @@ -23,6 +23,7 @@ import io.reactivex.Observable interface MainView : QkView { + val activityResumedIntent: Observable<*> val queryChangedIntent: Observable val composeIntent: Observable val drawerOpenIntent: Observable @@ -35,8 +36,10 @@ interface MainView : QkView { val confirmDeleteIntent: Observable val swipeConversationIntent: Observable val undoSwipeConversationIntent: Observable + val snackbarButtonIntent: Observable val backPressedIntent: Observable + fun requestPermissions() fun clearSearch() fun clearSelection() fun showDeleteDialog() diff --git a/presentation/src/main/java/feature/main/MainViewModel.kt b/presentation/src/main/java/feature/main/MainViewModel.kt index a291ae1a8..e9173f6f6 100644 --- a/presentation/src/main/java/feature/main/MainViewModel.kt +++ b/presentation/src/main/java/feature/main/MainViewModel.kt @@ -18,11 +18,7 @@ */ package feature.main -import android.Manifest import android.content.Context -import android.content.pm.PackageManager -import android.provider.Telephony -import android.support.v4.content.ContextCompat import com.moez.QKSMS.R import com.uber.autodispose.android.lifecycle.scope import com.uber.autodispose.kotlin.autoDisposable @@ -36,14 +32,15 @@ import interactor.MarkArchived import interactor.MarkBlocked import interactor.MarkUnarchived import interactor.MigratePreferences -import interactor.PartialSync +import interactor.SyncMessages import io.reactivex.Observable +import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.withLatestFrom -import io.realm.Realm +import manager.PermissionManager import manager.RatingManager -import model.SyncLog import repository.MessageRepository +import repository.SyncRepository import util.Preferences import util.extensions.removeAccents import java.util.concurrent.TimeUnit @@ -61,9 +58,11 @@ class MainViewModel : QkViewModel(MainState()) { @Inject lateinit var markBlocked: MarkBlocked @Inject lateinit var migratePreferences: MigratePreferences @Inject lateinit var navigator: Navigator - @Inject lateinit var partialSync: PartialSync + @Inject lateinit var permissionManager: PermissionManager @Inject lateinit var prefs: Preferences @Inject lateinit var ratingManager: RatingManager + @Inject lateinit var syncMessages: SyncMessages + @Inject lateinit var syncRepository: SyncRepository private val conversations by lazy { messageRepo.getConversations() } @@ -78,36 +77,21 @@ class MainViewModel : QkViewModel(MainState()) { disposables += markArchived disposables += markUnarchived disposables += migratePreferences - disposables += partialSync - - // If it's the first sync, reflect that in the ViewState - disposables += Realm.getDefaultInstance() - .where(SyncLog::class.java) - .findAll() - .asFlowable() - .filter { it.isLoaded } - .map { it.size == 0 } - .doOnNext { if (it) partialSync.execute(Unit) } + disposables += syncMessages + + // Show the syncing UI + disposables += syncRepository.syncProgress .distinctUntilChanged() .subscribe { syncing -> newState { it.copy(syncing = syncing) } } + + // Show the rating UI disposables += ratingManager.shouldShowRating .subscribe { show -> newState { it.copy(showRating = show) } } - // Migrate the preferences from 2.7.3 if necessary - migratePreferences.execute(Unit) - - val isNotDefaultSms = Telephony.Sms.getDefaultSmsPackage(context) != context.packageName - val hasSmsPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED - val hasContactPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED - if (isNotDefaultSms) { - partialSync.execute(Unit) - } - - if (isNotDefaultSms || !hasSmsPermission || !hasContactPermission) { - navigator.showSetupActivity() - } + // Migrate the preferences from 2.7.3 + migratePreferences.execute(Unit) ratingManager.addSession() markAllSeen.execute(Unit) @@ -116,14 +100,43 @@ class MainViewModel : QkViewModel(MainState()) { override fun bindView(view: MainView) { super.bindView(view) + if (!permissionManager.hasSmsAndContacts()) { + view.requestPermissions() + } + + // If the default SMS state or permission states change, update the ViewState + Observables.combineLatest( + view.activityResumedIntent.map { permissionManager.isDefaultSms() }.distinctUntilChanged(), + view.activityResumedIntent.map { permissionManager.hasSms() }.distinctUntilChanged(), + view.activityResumedIntent.map { permissionManager.hasContacts() }.distinctUntilChanged(), + { defaultSms, smsPermission, contactPermission -> + newState { it.copy(defaultSms = defaultSms, smsPermission = smsPermission, contactPermission = contactPermission) } + }) + .autoDisposable(view.scope()) + .subscribe() + + // If the SMS permission state changes from false to true, sync messages + view.activityResumedIntent + .map { permissionManager.hasSms() } + .distinctUntilChanged() + .skip(1) + .filter { hasSms -> hasSms } + .take(1) + .autoDisposable(view.scope()) + .subscribe { + syncMessages.execute(Unit) + if (!permissionManager.isDefaultSms()) { + navigator.showDefaultSmsDialog() + } + } + view.queryChangedIntent .debounce(200, TimeUnit.MILLISECONDS) .map { query -> query.removeAccents() } .withLatestFrom(state, { query, state -> if (state.page is Inbox) { val filteredConversations = if (query.isEmpty()) conversations - else conversations - .map { conversations -> conversations.filter { conversationFilter.filter(it, query) } } + else conversations.map { conversations -> conversations.filter { conversationFilter.filter(it, query) } } val page = state.page.copy(showClearButton = query.isNotEmpty(), data = filteredConversations) newState { it.copy(page = page) } @@ -260,6 +273,17 @@ class MainViewModel : QkViewModel(MainState()) { .autoDisposable(view.scope()) .subscribe { threadId -> markUnarchived.execute(listOf(threadId)) } + view.snackbarButtonIntent + .withLatestFrom(state, { _, state -> + when { + !state.smsPermission -> view.requestPermissions() + !state.defaultSms -> navigator.showDefaultSmsDialog() + !state.contactPermission -> view.requestPermissions() + } + }) + .autoDisposable(view.scope()) + .subscribe() + view.backPressedIntent .withLatestFrom(state, { _, state -> when { diff --git a/presentation/src/main/java/feature/settings/SettingsActivity.kt b/presentation/src/main/java/feature/settings/SettingsActivity.kt index 6299b1f6b..4a41ff686 100644 --- a/presentation/src/main/java/feature/settings/SettingsActivity.kt +++ b/presentation/src/main/java/feature/settings/SettingsActivity.kt @@ -105,11 +105,6 @@ class SettingsActivity : QkThemedActivity(), SettingsView { if (progressDialog.isShowing && !state.syncing) progressDialog.dismiss() else if (!progressDialog.isShowing && state.syncing) progressDialog.show() - defaultSms.summary = getString(when (state.isDefaultSmsApp) { - true -> R.string.settings_default_sms_summary_true - else -> R.string.settings_default_sms_summary_false - }) - themePreview.setBackgroundTint(state.theme) night.summary = state.nightModeSummary nightModeDialog.adapter.selectedItem = state.nightModeId diff --git a/presentation/src/main/java/feature/settings/SettingsState.kt b/presentation/src/main/java/feature/settings/SettingsState.kt index 997ca888a..d6ae51f8c 100644 --- a/presentation/src/main/java/feature/settings/SettingsState.kt +++ b/presentation/src/main/java/feature/settings/SettingsState.kt @@ -22,7 +22,6 @@ import util.Preferences data class SettingsState( val syncing: Boolean = false, - val isDefaultSmsApp: Boolean = false, val theme: Int = 0, val nightModeSummary: String = "", val nightModeId: Int = Preferences.NIGHT_MODE_OFF, diff --git a/presentation/src/main/java/feature/settings/SettingsViewModel.kt b/presentation/src/main/java/feature/settings/SettingsViewModel.kt index 1a9405fdd..61b51ef06 100644 --- a/presentation/src/main/java/feature/settings/SettingsViewModel.kt +++ b/presentation/src/main/java/feature/settings/SettingsViewModel.kt @@ -29,7 +29,7 @@ import common.util.Colors import common.util.DateFormatter import common.util.NightModeManager import injection.appComponent -import interactor.FullSync +import interactor.SyncMessages import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.withLatestFrom import timber.log.Timber @@ -46,17 +46,11 @@ class SettingsViewModel : QkViewModel(SettingsState @Inject lateinit var navigator: Navigator @Inject lateinit var nightModeManager: NightModeManager @Inject lateinit var prefs: Preferences - @Inject lateinit var fullSync: FullSync + @Inject lateinit var syncMessages: SyncMessages init { appComponent.inject(this) - disposables += prefs.defaultSms - .asObservable() - .subscribe { isDefaultSmsApp -> - newState { it.copy(isDefaultSmsApp = isDefaultSmsApp) } - } - disposables += colors.theme .subscribe { color -> newState { it.copy(theme = color) } } @@ -108,7 +102,7 @@ class SettingsViewModel : QkViewModel(SettingsState newState { it.copy(maxMmsSizeSummary = mmsSizeLabels[index], maxMmsSizeId = maxMmsSize) } } - disposables += fullSync + disposables += syncMessages } override fun bindView(view: SettingsView) { @@ -120,8 +114,6 @@ class SettingsViewModel : QkViewModel(SettingsState Timber.v("Preference click: ${context.resources.getResourceName(it.id)}") when (it.id) { - R.id.defaultSms -> navigator.showDefaultSmsDialog() - R.id.theme -> navigator.showThemePicker() R.id.night -> view.showNightModeDialog() @@ -158,7 +150,7 @@ class SettingsViewModel : QkViewModel(SettingsState R.id.sync -> { newState { it.copy(syncing = true) } - fullSync.execute(Unit, { + syncMessages.execute(Unit, { newState { it.copy(syncing = false) } }) } diff --git a/presentation/src/main/java/feature/setup/SetupActivity.kt b/presentation/src/main/java/feature/setup/SetupActivity.kt deleted file mode 100644 index 8f68c4ed5..000000000 --- a/presentation/src/main/java/feature/setup/SetupActivity.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package feature.setup - -import android.Manifest -import android.os.Bundle -import android.support.v4.app.ActivityCompat -import com.jakewharton.rxbinding2.view.clicks -import com.moez.QKSMS.R -import com.uber.autodispose.android.lifecycle.scope -import com.uber.autodispose.kotlin.autoDisposable -import injection.appComponent -import io.reactivex.subjects.PublishSubject -import io.reactivex.subjects.Subject -import kotlinx.android.synthetic.main.setup_activity.* -import common.Navigator -import common.base.QkThemedActivity -import javax.inject.Inject - -class SetupActivity : QkThemedActivity(), SetupView { - - override val viewModelClass = SetupViewModel::class - override val activityResumedIntent: Subject = PublishSubject.create() - override val skipIntent by lazy { skip.clicks() } - override val nextIntent by lazy { next.clicks() } - - @Inject lateinit var navigator: Navigator - - init { - appComponent.inject(this) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.setup_activity) - viewModel.bindView(this) - - colors.background - .autoDisposable(scope()) - .subscribe { color -> window.decorView.setBackgroundColor(color) } - } - - override fun onResume() { - super.onResume() - activityResumedIntent.onNext(Unit) - } - - override fun render(state: SetupState) { - } - - override fun requestDefaultSms() { - navigator.showDefaultSmsDialog() - } - - override fun requestPermissions() { - ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS), 0) - } - -} \ No newline at end of file diff --git a/presentation/src/main/java/feature/setup/SetupState.kt b/presentation/src/main/java/feature/setup/SetupState.kt deleted file mode 100644 index 248c5dae9..000000000 --- a/presentation/src/main/java/feature/setup/SetupState.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package feature.setup - -class SetupState \ No newline at end of file diff --git a/presentation/src/main/java/feature/setup/SetupView.kt b/presentation/src/main/java/feature/setup/SetupView.kt deleted file mode 100644 index 380b40cb7..000000000 --- a/presentation/src/main/java/feature/setup/SetupView.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package feature.setup - -import io.reactivex.Observable -import common.base.QkView -import feature.setup.SetupState - -interface SetupView : QkView { - - val activityResumedIntent: Observable<*> - val skipIntent: Observable<*> - val nextIntent: Observable<*> - - fun requestDefaultSms() - fun requestPermissions() - fun finish() - -} \ No newline at end of file diff --git a/presentation/src/main/java/feature/setup/SetupViewModel.kt b/presentation/src/main/java/feature/setup/SetupViewModel.kt deleted file mode 100644 index 1f4e69bd7..000000000 --- a/presentation/src/main/java/feature/setup/SetupViewModel.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package feature.setup - -import android.content.Context -import android.provider.Telephony -import com.uber.autodispose.android.lifecycle.scope -import com.uber.autodispose.kotlin.autoDisposable -import injection.appComponent -import manager.PermissionManager -import common.base.QkViewModel -import feature.setup.SetupState -import feature.setup.SetupView -import javax.inject.Inject - -class SetupViewModel : QkViewModel(SetupState()) { - - @Inject lateinit var context: Context - @Inject lateinit var permissions: PermissionManager - - init { - appComponent.inject(this) - } - - override fun bindView(view: SetupView) { - super.bindView(view) - - view.activityResumedIntent - .autoDisposable(view.scope()) - .subscribe { - val isDefault = Telephony.Sms.getDefaultSmsPackage(context) == context.packageName - - if (!permissions.hasSmsAndContacts()) view.requestPermissions() - else if (isDefault) view.finish() - } - - view.skipIntent - .autoDisposable(view.scope()) - .subscribe { view.finish() } - - view.nextIntent - .autoDisposable(view.scope()) - .subscribe { view.requestDefaultSms() } - } - -} \ No newline at end of file diff --git a/presentation/src/main/java/injection/AppComponent.kt b/presentation/src/main/java/injection/AppComponent.kt index bd201096b..368dbba4a 100644 --- a/presentation/src/main/java/injection/AppComponent.kt +++ b/presentation/src/main/java/injection/AppComponent.kt @@ -50,8 +50,6 @@ import feature.settings.SettingsActivity import feature.settings.SettingsViewModel import feature.settings.about.AboutActivity import feature.settings.about.AboutViewModel -import feature.setup.SetupActivity -import feature.setup.SetupViewModel import feature.themepicker.ThemePickerActivity import feature.themepicker.ThemePickerViewModel import feature.widget.WidgetAdapter @@ -78,7 +76,6 @@ interface AppComponent { fun inject(application: QKApplication) fun inject(activity: MainActivity) - fun inject(activity: SetupActivity) fun inject(activity: AboutActivity) fun inject(activity: BlockedActivity) fun inject(activity: ComposeActivity) @@ -121,7 +118,6 @@ interface AppComponent { fun inject(view: Separator) fun inject(viewModel: MainViewModel) - fun inject(viewModel: SetupViewModel) fun inject(viewModel: AboutViewModel) fun inject(viewModel: BlockedViewModel) fun inject(viewModel: ComposeViewModel) diff --git a/presentation/src/main/java/receiver/DefaultSmsChangedReceiver.kt b/presentation/src/main/java/receiver/DefaultSmsChangedReceiver.kt index d9f37bcd6..36d155912 100644 --- a/presentation/src/main/java/receiver/DefaultSmsChangedReceiver.kt +++ b/presentation/src/main/java/receiver/DefaultSmsChangedReceiver.kt @@ -25,25 +25,22 @@ import android.os.Build import android.provider.Telephony import android.support.annotation.RequiresApi import injection.appComponent +import interactor.SyncMessages import util.Preferences -import interactor.PartialSync import javax.inject.Inject class DefaultSmsChangedReceiver : BroadcastReceiver() { - @Inject lateinit var partialSync: PartialSync @Inject lateinit var prefs: Preferences + @Inject lateinit var syncMessages: SyncMessages @RequiresApi(Build.VERSION_CODES.N) override fun onReceive(context: Context, intent: Intent) { appComponent.inject(this) - val isDefaultSmsApp = intent.getBooleanExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, false) - prefs.defaultSms.set(isDefaultSmsApp) - - if (isDefaultSmsApp) { + if (intent.getBooleanExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, false)) { val pendingResult = goAsync() - partialSync.execute(Unit, { pendingResult.finish() }) + syncMessages.execute(Unit, { pendingResult.finish() }) } } diff --git a/presentation/src/main/res/layout/main_activity.xml b/presentation/src/main/res/layout/main_activity.xml index 0b7d8d5be..c9716eb40 100644 --- a/presentation/src/main/res/layout/main_activity.xml +++ b/presentation/src/main/res/layout/main_activity.xml @@ -22,7 +22,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + tools:background="@color/white"> + + + + + + + + + + + + + + - + app:textColor="primary" + app:textSize="primary" + tools:text="Love texting again" /> + app:textColor="secondary" + app:textSize="secondary" + tools:text="Make QKSMS your default SMS app" /> - - - - - - - - - + app:layout_constraintTop_toTopOf="@id/snackbarTitle" + app:textColor="theme" + app:textSize="secondary" + tools:text="Change" /> - + - diff --git a/presentation/src/main/res/layout/settings_activity.xml b/presentation/src/main/res/layout/settings_activity.xml index acc455821..8552aae7c 100644 --- a/presentation/src/main/res/layout/settings_activity.xml +++ b/presentation/src/main/res/layout/settings_activity.xml @@ -56,18 +56,6 @@ android:paddingBottom="8dp" android:paddingTop="8dp"> - - - - diff --git a/presentation/src/main/res/layout/setup_activity.xml b/presentation/src/main/res/layout/setup_activity.xml deleted file mode 100644 index 0cb51665f..000000000 --- a/presentation/src/main/res/layout/setup_activity.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/values-bn/strings.xml b/presentation/src/main/res/values-bn/strings.xml index 317f7db1e..08bf274ef 100644 --- a/presentation/src/main/res/values-bn/strings.xml +++ b/presentation/src/main/res/values-bn/strings.xml @@ -28,8 +28,8 @@ Search inbox… রচনা করুন QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-cs/strings.xml b/presentation/src/main/res/values-cs/strings.xml index 590143b7e..f31baf2e8 100644 --- a/presentation/src/main/res/values-cs/strings.xml +++ b/presentation/src/main/res/values-cs/strings.xml @@ -28,8 +28,8 @@ Hledat… Nová zpráva QKSMS+ - Zamilujte si znovu SMS - Nastavit QKSMS jako výchozí aplikaci pro zprávy SMS + Zamilujte si znovu SMS + Nastavit QKSMS jako výchozí aplikaci pro zprávy SMS Přeskočit Pokračovat Vymazat diff --git a/presentation/src/main/res/values-da/strings.xml b/presentation/src/main/res/values-da/strings.xml index 657f40c53..76536519b 100644 --- a/presentation/src/main/res/values-da/strings.xml +++ b/presentation/src/main/res/values-da/strings.xml @@ -28,8 +28,8 @@ Søg i Indbakke… Angiv et navn eller nummer QKSMS+ - Elsk at SMS\'e igen - Gør QKSMS til din standard SMS-app + Elsk at SMS\'e igen + Gør QKSMS til din standard SMS-app Overspring Fortsæt Ryd diff --git a/presentation/src/main/res/values-de/strings.xml b/presentation/src/main/res/values-de/strings.xml index de3848859..010711b30 100644 --- a/presentation/src/main/res/values-de/strings.xml +++ b/presentation/src/main/res/values-de/strings.xml @@ -28,8 +28,8 @@ In Posteingang suchen… Verfassen QKSMS+ - Du wirst SMS wieder lieben - QKSMS als Standard-SMS-App festlegen + Du wirst SMS wieder lieben + QKSMS als Standard-SMS-App festlegen Überspringen Weiter Leeren diff --git a/presentation/src/main/res/values-es/strings.xml b/presentation/src/main/res/values-es/strings.xml index f280d9bc8..4ad4a6585 100644 --- a/presentation/src/main/res/values-es/strings.xml +++ b/presentation/src/main/res/values-es/strings.xml @@ -28,8 +28,8 @@ Buscar mensaje… Escriba un nombre o número QKSMS+ - Ama mensajear otra vez - Haga de QKSMS su aplicación SMS prederminada + Ama mensajear otra vez + Haga de QKSMS su aplicación SMS prederminada Omitir Continuar Borrar diff --git a/presentation/src/main/res/values-fa/strings.xml b/presentation/src/main/res/values-fa/strings.xml index dd876311c..e89dd1ed3 100644 --- a/presentation/src/main/res/values-fa/strings.xml +++ b/presentation/src/main/res/values-fa/strings.xml @@ -28,8 +28,8 @@ یافتن پیامک… Compose نسخه پیشرفته - فرستادن مجدد - انتخاب به عنوان برنامه پیشفرض + فرستادن مجدد + انتخاب به عنوان برنامه پیشفرض بیخیال ادامه پاک کردن diff --git a/presentation/src/main/res/values-fi/strings.xml b/presentation/src/main/res/values-fi/strings.xml index eb75b59c3..23119f403 100644 --- a/presentation/src/main/res/values-fi/strings.xml +++ b/presentation/src/main/res/values-fi/strings.xml @@ -28,8 +28,8 @@ Search inbox… Kirjoita QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-fr/strings.xml b/presentation/src/main/res/values-fr/strings.xml index 5836cf467..2562ed343 100644 --- a/presentation/src/main/res/values-fr/strings.xml +++ b/presentation/src/main/res/values-fr/strings.xml @@ -28,8 +28,8 @@ Rechercher dans les conversations… Entrez un nom ou un numéro QKSMS+ - Réapprenez à aimer les textos - Faire de QKSMS l\'application par défaut pour les SMS + Réapprenez à aimer les textos + Faire de QKSMS l\'application par défaut pour les SMS Plus tard Continuer Effacer diff --git a/presentation/src/main/res/values-hi/strings.xml b/presentation/src/main/res/values-hi/strings.xml index e16c4d134..449dfd84c 100644 --- a/presentation/src/main/res/values-hi/strings.xml +++ b/presentation/src/main/res/values-hi/strings.xml @@ -28,8 +28,8 @@ Search inbox… रचना QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-hr/strings.xml b/presentation/src/main/res/values-hr/strings.xml index d66763884..af99ccc9a 100644 --- a/presentation/src/main/res/values-hr/strings.xml +++ b/presentation/src/main/res/values-hr/strings.xml @@ -28,8 +28,8 @@ Pretraži poruke… Unesite ime ili broj QKSMS+ - Ponovno zavolite poruke - Postavite QKSMS kao zadanu aplikaciju za SMS + Ponovno zavolite poruke + Postavite QKSMS kao zadanu aplikaciju za SMS Preskoči Nastavi Očisti diff --git a/presentation/src/main/res/values-hu/strings.xml b/presentation/src/main/res/values-hu/strings.xml index ce563f4f3..0f48e9462 100644 --- a/presentation/src/main/res/values-hu/strings.xml +++ b/presentation/src/main/res/values-hu/strings.xml @@ -28,8 +28,8 @@ Search inbox… Üzenetírás QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-in/strings.xml b/presentation/src/main/res/values-in/strings.xml index 22212b249..c5f8b4993 100644 --- a/presentation/src/main/res/values-in/strings.xml +++ b/presentation/src/main/res/values-in/strings.xml @@ -28,8 +28,8 @@ Cari kotak masuk… Tulis Pesan baru QKSMS+ - Love texting again - Buat QKSMS aplikasi SMS default Anda + Love texting again + Buat QKSMS aplikasi SMS default Anda Lewati Lanjutkan Clear diff --git a/presentation/src/main/res/values-it/strings.xml b/presentation/src/main/res/values-it/strings.xml index 7da1b9e7c..341be1a4a 100644 --- a/presentation/src/main/res/values-it/strings.xml +++ b/presentation/src/main/res/values-it/strings.xml @@ -28,8 +28,8 @@ Cerca posta in arrivo… Scrivi QKSMS+ - Love texting again - Rendi QKSMS l\'app SMS predefinita + Love texting again + Rendi QKSMS l\'app SMS predefinita Salta Continua Azzera diff --git a/presentation/src/main/res/values-iw/strings.xml b/presentation/src/main/res/values-iw/strings.xml index aa96ee75d..5506a4578 100644 --- a/presentation/src/main/res/values-iw/strings.xml +++ b/presentation/src/main/res/values-iw/strings.xml @@ -28,8 +28,8 @@ Search inbox… כתוב הודעה QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-ja/strings.xml b/presentation/src/main/res/values-ja/strings.xml index bbd77d71b..dc5a06882 100644 --- a/presentation/src/main/res/values-ja/strings.xml +++ b/presentation/src/main/res/values-ja/strings.xml @@ -28,8 +28,8 @@ 受信トレイを検索… 作成 QKSMS+ - 愛のテキストメッセージをふたたび - QKSMS をデフォルトの SMS アプリにします + 愛のテキストメッセージをふたたび + QKSMS をデフォルトの SMS アプリにします スキップ 続行 クリア diff --git a/presentation/src/main/res/values-ko/strings.xml b/presentation/src/main/res/values-ko/strings.xml index 5ca91e9a9..92caa67e6 100644 --- a/presentation/src/main/res/values-ko/strings.xml +++ b/presentation/src/main/res/values-ko/strings.xml @@ -28,8 +28,8 @@ 수신함에서 찾기... 문자작성 QKSMS+ - 다시 문자를 즐겁게 - QKSMS를 기본 SMS 앱으로 설정하세요 + 다시 문자를 즐겁게 + QKSMS를 기본 SMS 앱으로 설정하세요 건너뛰기 계속 비우기 diff --git a/presentation/src/main/res/values-lt/strings.xml b/presentation/src/main/res/values-lt/strings.xml index a074c098e..850b054b2 100644 --- a/presentation/src/main/res/values-lt/strings.xml +++ b/presentation/src/main/res/values-lt/strings.xml @@ -28,8 +28,8 @@ Search inbox… Rašyti QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-ne/strings.xml b/presentation/src/main/res/values-ne/strings.xml index 6f8927197..daa919b7c 100644 --- a/presentation/src/main/res/values-ne/strings.xml +++ b/presentation/src/main/res/values-ne/strings.xml @@ -28,8 +28,8 @@ Search inbox… Compose QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-nl/strings.xml b/presentation/src/main/res/values-nl/strings.xml index d4a95f129..a8516d25f 100644 --- a/presentation/src/main/res/values-nl/strings.xml +++ b/presentation/src/main/res/values-nl/strings.xml @@ -28,8 +28,8 @@ Doorzoek inbox… Type een naam of nummer QKSMS+ - Love texting again - Maak QKSMS jouw standaard SMS app + Love texting again + Maak QKSMS jouw standaard SMS app Overslaan Verder Annuleren diff --git a/presentation/src/main/res/values-no/strings.xml b/presentation/src/main/res/values-no/strings.xml index 42a3b18da..2c7371ab5 100644 --- a/presentation/src/main/res/values-no/strings.xml +++ b/presentation/src/main/res/values-no/strings.xml @@ -28,8 +28,8 @@ Search inbox… Type a name or number QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-pl/strings.xml b/presentation/src/main/res/values-pl/strings.xml index 88e7be050..1b0788b44 100644 --- a/presentation/src/main/res/values-pl/strings.xml +++ b/presentation/src/main/res/values-pl/strings.xml @@ -28,8 +28,8 @@ Przeszukaj skrzynkę odbiorczą… Nowa wiadomość QKSMS+ - Znów kocham pisać wiadomości - Uczyń QKSMS domyślną aplikacja do obsługi SMSów + Znów kocham pisać wiadomości + Uczyń QKSMS domyślną aplikacja do obsługi SMSów Pomiń Kontynuuj Wyczyść diff --git a/presentation/src/main/res/values-pt-rBR/strings.xml b/presentation/src/main/res/values-pt-rBR/strings.xml index 7baebce56..6dc9b2370 100644 --- a/presentation/src/main/res/values-pt-rBR/strings.xml +++ b/presentation/src/main/res/values-pt-rBR/strings.xml @@ -28,8 +28,8 @@ Pesquisar caixa de entrada… Nova Mensagem QKSMS+ - Volta a amar os SMS - Tornar QKSMS a aplicação padrão + Volta a amar os SMS + Tornar QKSMS a aplicação padrão Pular Continuar Limpar diff --git a/presentation/src/main/res/values-pt/strings.xml b/presentation/src/main/res/values-pt/strings.xml index 4eb4a6595..3bfba1b9a 100644 --- a/presentation/src/main/res/values-pt/strings.xml +++ b/presentation/src/main/res/values-pt/strings.xml @@ -28,8 +28,8 @@ Pesquisar caixa de entrada… Nova mensagem QKSMS+ - Volta a amar os SMS - Tornar QKSMS a aplicação padrão + Volta a amar os SMS + Tornar QKSMS a aplicação padrão Ignorar Continuar Limpar diff --git a/presentation/src/main/res/values-ro/strings.xml b/presentation/src/main/res/values-ro/strings.xml index 3f40907e2..5a60c58d7 100644 --- a/presentation/src/main/res/values-ro/strings.xml +++ b/presentation/src/main/res/values-ro/strings.xml @@ -28,8 +28,8 @@ Caută în inbox... Compune QKSMS+ - Iubesc să scriu din nou - Fă QKSMS aplicația de mesaje prestabilită + Iubesc să scriu din nou + Fă QKSMS aplicația de mesaje prestabilită Sari Continue Clear diff --git a/presentation/src/main/res/values-ru/strings.xml b/presentation/src/main/res/values-ru/strings.xml index 09160add0..babb6a112 100644 --- a/presentation/src/main/res/values-ru/strings.xml +++ b/presentation/src/main/res/values-ru/strings.xml @@ -28,8 +28,8 @@ Поиск во входящих… Написать QKSMS+ - Снова нравится писать - Сделать QKSMS приложением для SMS по умолчанию + Снова нравится писать + Сделать QKSMS приложением для SMS по умолчанию Пропустить Продолжить Очистить diff --git a/presentation/src/main/res/values-sk/strings.xml b/presentation/src/main/res/values-sk/strings.xml index 34c7b304d..5ac06cadd 100644 --- a/presentation/src/main/res/values-sk/strings.xml +++ b/presentation/src/main/res/values-sk/strings.xml @@ -28,8 +28,8 @@ Search inbox… Nová správa QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-sr/strings.xml b/presentation/src/main/res/values-sr/strings.xml index 06e92a0db..b7cab14c0 100644 --- a/presentation/src/main/res/values-sr/strings.xml +++ b/presentation/src/main/res/values-sr/strings.xml @@ -28,8 +28,8 @@ Search inbox… Састављање QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-sv/strings.xml b/presentation/src/main/res/values-sv/strings.xml index 6c40bcbdb..4fd0f82f9 100644 --- a/presentation/src/main/res/values-sv/strings.xml +++ b/presentation/src/main/res/values-sv/strings.xml @@ -28,8 +28,8 @@ Sök i inkorg… Nytt meddelande QKSMS+ - Love texting again - Gör QKSMS till din standard SMS-app + Love texting again + Gör QKSMS till din standard SMS-app Hoppa över Fortsätt Rensa diff --git a/presentation/src/main/res/values-tl/strings.xml b/presentation/src/main/res/values-tl/strings.xml index 151a02c7a..1d74ee76a 100644 --- a/presentation/src/main/res/values-tl/strings.xml +++ b/presentation/src/main/res/values-tl/strings.xml @@ -28,8 +28,8 @@ Search inbox… Sumulat QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-tr/strings.xml b/presentation/src/main/res/values-tr/strings.xml index 340dc4edb..9f6d06e07 100644 --- a/presentation/src/main/res/values-tr/strings.xml +++ b/presentation/src/main/res/values-tr/strings.xml @@ -28,8 +28,8 @@ Search inbox… Oluştur QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values-vi/strings.xml b/presentation/src/main/res/values-vi/strings.xml index 2b1d10450..460ecc323 100644 --- a/presentation/src/main/res/values-vi/strings.xml +++ b/presentation/src/main/res/values-vi/strings.xml @@ -28,8 +28,8 @@ Tìm kiếm các tin đã nhận… Nhập tên hoặc số điện thoại QKSMS+ - Thích nhắn tin trở lại - Đặt QKSMS là ứng dụng tin nhắn mặc định + Thích nhắn tin trở lại + Đặt QKSMS là ứng dụng tin nhắn mặc định Bỏ qua Tiếp tục Xóa diff --git a/presentation/src/main/res/values-zh-rCN/strings.xml b/presentation/src/main/res/values-zh-rCN/strings.xml index d59017ebd..069fb43e3 100644 --- a/presentation/src/main/res/values-zh-rCN/strings.xml +++ b/presentation/src/main/res/values-zh-rCN/strings.xml @@ -28,8 +28,8 @@ Search inbox… 撰写 QKSMS+ - Love texting again - 使 QKSMS 成为您的默认短信应用 + Love texting again + 使 QKSMS 成为您的默认短信应用 跳过 继续 清除 diff --git a/presentation/src/main/res/values-zh/strings.xml b/presentation/src/main/res/values-zh/strings.xml index 648608836..039b9b514 100644 --- a/presentation/src/main/res/values-zh/strings.xml +++ b/presentation/src/main/res/values-zh/strings.xml @@ -28,8 +28,8 @@ Search inbox… 編輯 QKSMS+ - Love texting again - Make QKSMS your default SMS app + Love texting again + Make QKSMS your default SMS app Skip Continue Clear diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 3c7698325..1856218de 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -29,8 +29,6 @@ Type a name or number QKSMS+ - Love texting again - Make QKSMS your default SMS app Skip Continue @@ -44,13 +42,20 @@ Unarchive Block Delete - Optimizing database, this might take a minute… + Syncing messages… You: %s Your conversations will appear here No results Your archived conversations will appear here Your scheduled messages will appear here Start new conversation + Love texting again + Make QKSMS your default SMS app + Change + Permission required + QKSMS needs permission to send and view SMS messages + QKSMS needs permission to view your contacts + Allow Inbox Archived @@ -104,9 +109,6 @@ General QK Reply - Default SMS app - QKSMS is your default SMS app - Set QKSMS as your default SMS app Theme Night mode Pure black night mode