refactor: Remove references to QKSMS+

This commit is contained in:
Cian Ormond
2026-09-27 00:02:09 -04:00
committed by Inhishonor
parent 4b942fe71c
commit 2cb3c6fe19
38 changed files with 217 additions and 1159 deletions
@@ -1,47 +0,0 @@
/*
* Copyright (C) 2020 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.manager
import android.app.Activity
import io.reactivex.Observable
interface BillingManager {
companion object {
const val SKU_PLUS = "remove_ads"
const val SKU_PLUS_DONATE = "qksms_plus_donate"
}
data class Product(
val sku: String,
val price: String,
val priceCurrencyCode: String
)
val products: Observable<List<Product>>
val upgradeStatus: Observable<Boolean>
suspend fun checkForPurchases()
suspend fun queryProducts()
suspend fun initiatePurchaseFlow(activity: Activity, sku: String)
}
@@ -107,7 +107,6 @@
<activity android:name=".feature.messageutils.MessageUtilsActivity" />
<activity android:name=".feature.settings.SettingsActivity" />
<activity android:name=".feature.settings.about.AboutActivity" />
<activity android:name=".feature.plus.PlusActivity" />
<activity
android:name=".feature.gallery.GalleryActivity"
android:theme="@style/AppTheme.Gallery" />
@@ -30,7 +30,6 @@ import android.provider.Settings
import android.provider.Telephony
import androidx.core.net.toUri
import dev.octoshrimpy.quik.BuildConfig
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.manager.PermissionManager
import javax.inject.Inject
import dev.octoshrimpy.quik.feature.notificationprefs.NotificationPrefsActivity
@@ -42,7 +41,6 @@ import dev.octoshrimpy.quik.manager.NotificationManager
*/
class ExternalNavigator @Inject constructor(
context: Context,
private val billingManager: BillingManager,
private val permissions: PermissionManager,
private val notificationManager: NotificationManager
) : QkNavigator(context) {
@@ -98,15 +96,15 @@ class ExternalNavigator @Inject constructor(
intent.data = "mailto:".toUri()
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("quik@octo.sh"))
intent.putExtra(Intent.EXTRA_SUBJECT, "QUIK Support")
intent.putExtra(Intent.EXTRA_TEXT, StringBuilder("\n\n")
.append("\n\n--- Please write your message above this line ---\n\n")
.append("Package: ${context.packageName}\n")
.append("Version: ${BuildConfig.VERSION_NAME}\n")
.append("Device: ${Build.BRAND} ${Build.MODEL}\n")
.append("SDK: ${Build.VERSION.SDK_INT}\n")
.append("Upgraded"
.takeIf { billingManager.upgradeStatus.blockingFirst() } ?: "")
.toString())
intent.putExtra(
Intent.EXTRA_TEXT, StringBuilder("\n\n")
.append("\n\n--- Please write your message above this line ---\n\n")
.append("Package: ${context.packageName}\n")
.append("Version: ${BuildConfig.VERSION_NAME}\n")
.append("Device: ${Build.BRAND} ${Build.MODEL}\n")
.append("SDK: ${Build.VERSION.SDK_INT}\n")
.toString()
)
startActivityExternal(intent)
}
@@ -32,7 +32,6 @@ import dev.octoshrimpy.quik.feature.conversationinfo.ConversationInfoActivity
import dev.octoshrimpy.quik.feature.gallery.GalleryActivity
import dev.octoshrimpy.quik.feature.main.MainActivity
import dev.octoshrimpy.quik.feature.messageutils.MessageUtilsActivity
import dev.octoshrimpy.quik.feature.plus.PlusActivity
import dev.octoshrimpy.quik.feature.scheduled.ScheduledActivity
import dev.octoshrimpy.quik.feature.settings.SettingsActivity
import dev.octoshrimpy.quik.model.ScheduledMessage
@@ -43,14 +42,6 @@ import javax.inject.Singleton
class Navigator @Inject constructor(
context: Context
) : QkNavigator(context) {
/**
* @param source String to indicate where this QKSMS+ screen was launched from. This should be
* one of [main_menu, compose_schedule, settings_night, settings_theme]
*/
fun showQksmsPlusActivity(source: String) {
startActivity(Intent(context, PlusActivity::class.java))
}
fun showMainActivity() {
startActivity(Intent(context, MainActivity::class.java))
}
@@ -39,7 +39,6 @@ import dev.octoshrimpy.quik.common.util.FileLoggingTree
import dev.octoshrimpy.quik.injection.AppComponentManager
import dev.octoshrimpy.quik.injection.appComponent
import dev.octoshrimpy.quik.interactor.SpeakThreads
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.manager.ReferralManager
import dev.octoshrimpy.quik.migration.QkMigration
import dev.octoshrimpy.quik.migration.QkRealmMigration
@@ -59,17 +58,25 @@ class QKApplication : Application(), HasActivityInjector, HasBroadcastReceiverIn
* Inject these so that they are forced to initialize
*/
@Suppress("unused")
@Inject lateinit var qkMigration: QkMigration
@Inject
lateinit var qkMigration: QkMigration
@Inject lateinit var billingManager: BillingManager
@Inject lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>
@Inject lateinit var dispatchingBroadcastReceiverInjector: DispatchingAndroidInjector<BroadcastReceiver>
@Inject lateinit var dispatchingServiceInjector: DispatchingAndroidInjector<Service>
@Inject lateinit var fileLoggingTree: FileLoggingTree
@Inject lateinit var nightModeManager: NightModeManager
@Inject lateinit var realmMigration: QkRealmMigration
@Inject lateinit var referralManager: ReferralManager
@Inject lateinit var workerFactory: WorkerFactory
@Inject
lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>
@Inject
lateinit var dispatchingBroadcastReceiverInjector: DispatchingAndroidInjector<BroadcastReceiver>
@Inject
lateinit var dispatchingServiceInjector: DispatchingAndroidInjector<Service>
@Inject
lateinit var fileLoggingTree: FileLoggingTree
@Inject
lateinit var nightModeManager: NightModeManager
@Inject
lateinit var realmMigration: QkRealmMigration
@Inject
lateinit var referralManager: ReferralManager
@Inject
lateinit var workerFactory: WorkerFactory
override fun onCreate() {
super.onCreate()
@@ -91,8 +98,6 @@ class QKApplication : Application(), HasActivityInjector, HasBroadcastReceiverIn
GlobalScope.launch(Dispatchers.IO) {
referralManager.trackReferrer()
billingManager.checkForPurchases()
billingManager.queryProducts()
}
nightModeManager.updateCurrentTheme()
@@ -1,21 +0,0 @@
package dev.octoshrimpy.quik.common.util
import android.app.Activity
import dev.octoshrimpy.quik.manager.BillingManager
import io.reactivex.Observable
import io.reactivex.subjects.BehaviorSubject
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class BillingManagerImpl @Inject constructor(
): BillingManager {
override val products: Observable<List<BillingManager.Product>> = BehaviorSubject.createDefault(listOf())
override val upgradeStatus: Observable<Boolean> = BehaviorSubject.createDefault(true)
override suspend fun checkForPurchases() = Unit
override suspend fun queryProducts() = Unit
override suspend fun initiatePurchaseFlow(activity: Activity, sku: String) = Unit
}
@@ -201,16 +201,6 @@ class BackupController : QkController<BackupControllerBinding, BackupView, Backu
selectedBackupDetailsDialog.setShowing(state.selectedBackupDetails != null)
stopRestoreDialog.setShowing(state.showStopRestoreDialog)
binding.fabIcon.setImageResource(when (state.upgraded) {
true -> R.drawable.ic_file_upload_black_24dp
false -> R.drawable.ic_star_black_24dp
})
binding.fabLabel.setText(when (state.upgraded) {
true -> R.string.backup_now
false -> R.string.title_qksms_plus
})
}
override fun setBackupLocationClicks(): Observable<*> = binding.location.clicks()
@@ -27,7 +27,6 @@ import dev.octoshrimpy.quik.common.base.QkPresenter
import dev.octoshrimpy.quik.common.util.DateFormatter
import dev.octoshrimpy.quik.common.util.extensions.makeToast
import dev.octoshrimpy.quik.interactor.PerformBackup
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.repository.BackupRepository
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.rxkotlin.plusAssign
@@ -37,7 +36,6 @@ import javax.inject.Inject
class BackupPresenter @Inject constructor(
private val backupRepo: BackupRepository,
private val billingManager: BillingManager,
private val context: Context,
private val dateFormatter: DateFormatter,
private val navigator: Navigator,
@@ -46,111 +44,106 @@ class BackupPresenter @Inject constructor(
init {
disposables += backupRepo.getBackupProgress()
.sample(16, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.subscribe { progress -> newState { copy(backupProgress = progress) } }
.sample(16, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.subscribe { progress -> newState { copy(backupProgress = progress) } }
disposables += backupRepo.getRestoreProgress()
.sample(16, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.subscribe { progress -> newState { copy(restoreProgress = progress) } }
disposables += billingManager.upgradeStatus
.subscribe { upgraded -> newState { copy(upgraded = upgraded) } }
.sample(16, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.subscribe { progress -> newState { copy(restoreProgress = progress) } }
}
override fun bindIntents(view: BackupView) {
super.bindIntents(view)
view.setBackupLocationClicks()
.observeOn(AndroidSchedulers.mainThread())
.autoDisposable(view.scope())
.subscribe { view.selectFolder(backupRepo.getBackupPathUriForPicker()) }
.observeOn(AndroidSchedulers.mainThread())
.autoDisposable(view.scope())
.subscribe { view.selectFolder(backupRepo.getBackupPathUriForPicker()) }
view.restoreClicks()
.withLatestFrom(
backupRepo.getBackupProgress(),
backupRepo.getRestoreProgress(),
billingManager.upgradeStatus)
{ _, backupProgress, restoreProgress, upgraded ->
when {
!upgraded -> context.makeToast(R.string.backup_restore_error_plus)
backupProgress.running -> context.makeToast(R.string.backup_restore_error_backup)
restoreProgress.running -> context.makeToast(R.string.backup_restore_error_restore)
else -> view.selectFile(backupRepo.getBackupPathUriForPicker())
}
.withLatestFrom(
backupRepo.getBackupProgress(),
backupRepo.getRestoreProgress(),
)
{ _, backupProgress, restoreProgress ->
when {
backupProgress.running -> context.makeToast(R.string.backup_restore_error_backup)
restoreProgress.running -> context.makeToast(R.string.backup_restore_error_restore)
else -> view.selectFile(backupRepo.getBackupPathUriForPicker())
}
.autoDisposable(view.scope())
.subscribe()
}
.autoDisposable(view.scope())
.subscribe()
view.backupClicks()
.withLatestFrom(billingManager.upgradeStatus) { _, upgraded -> upgraded }
.autoDisposable(view.scope())
.subscribe { upgraded ->
when {
backupRepo.getBackupDocumentTree() == null -> {
newState { copy(showLocationRationale = true) }
}
!upgraded -> navigator.showQksmsPlusActivity("backup_fab")
upgraded -> performBackup.execute(Unit)
.autoDisposable(view.scope())
.subscribe {
when {
backupRepo.getBackupDocumentTree() == null -> newState {
copy(showLocationRationale = true)
}
}
performBackup.execute(Unit)
}
view.locationRationaleConfirmClicks()
.doOnNext { newState { copy(showLocationRationale = false) } }
.autoDisposable(view.scope())
.subscribe { view.selectFolder(backupRepo.getBackupPathUriForPicker()) }
.doOnNext { newState { copy(showLocationRationale = false) } }
.autoDisposable(view.scope())
.subscribe { view.selectFolder(backupRepo.getBackupPathUriForPicker()) }
view.locationRationaleCancelClicks()
.doOnNext { newState { copy(showLocationRationale = false) } }
.autoDisposable(view.scope())
.subscribe()
.doOnNext { newState { copy(showLocationRationale = false) } }
.autoDisposable(view.scope())
.subscribe()
view.selectedBackupErrorClicks()
.autoDisposable(view.scope())
.subscribe { newState { copy(showSelectedBackupError = false) } }
.autoDisposable(view.scope())
.subscribe { newState { copy(showSelectedBackupError = false) } }
view.confirmRestoreBackupConfirmClicks()
.doOnNext { newState { copy(selectedBackupDetails = null) } }
.withLatestFrom(view.documentSelected()) { _, backup -> backup }
.autoDisposable(view.scope())
.subscribe { backup -> RestoreBackupService.start(context, backup) }
.doOnNext { newState { copy(selectedBackupDetails = null) } }
.withLatestFrom(view.documentSelected()) { _, backup -> backup }
.autoDisposable(view.scope())
.subscribe { backup -> RestoreBackupService.start(context, backup) }
view.confirmRestoreBackupCancelClicks()
.doOnNext { newState { copy(selectedBackupDetails = null) } }
.autoDisposable(view.scope())
.subscribe()
.doOnNext { newState { copy(selectedBackupDetails = null) } }
.autoDisposable(view.scope())
.subscribe()
view.stopRestoreClicks()
.autoDisposable(view.scope())
.subscribe { newState { copy(showStopRestoreDialog = true) } }
.autoDisposable(view.scope())
.subscribe { newState { copy(showStopRestoreDialog = true) } }
view.stopRestoreConfirmed()
.doOnNext { newState { copy(showStopRestoreDialog = false) } }
.autoDisposable(view.scope())
.subscribe { backupRepo.stopRestore() }
.doOnNext { newState { copy(showStopRestoreDialog = false) } }
.autoDisposable(view.scope())
.subscribe { backupRepo.stopRestore() }
view.stopRestoreCancel()
.autoDisposable(view.scope())
.subscribe { newState { copy(showStopRestoreDialog = false) } }
.autoDisposable(view.scope())
.subscribe { newState { copy(showStopRestoreDialog = false) } }
view.documentTreeSelected()
.autoDisposable(view.scope())
.subscribe { uri -> backupRepo.persistBackupDirectory(uri) }
.autoDisposable(view.scope())
.subscribe { uri -> backupRepo.persistBackupDirectory(uri) }
view.documentSelected()
.observeOn(Schedulers.io())
.autoDisposable(view.scope())
.subscribe { uri ->
try {
val backupFile = backupRepo.parseBackup(uri)
val date = dateFormatter.getDetailedTimestamp(backupFile.date)
val details = context.getString(R.string.backup_details, date, backupFile.messages)
newState { copy(selectedBackupDetails = details) }
} catch (e: Exception) {
newState { copy(showSelectedBackupError = true) }
}
.observeOn(Schedulers.io())
.autoDisposable(view.scope())
.subscribe { uri ->
try {
val backupFile = backupRepo.parseBackup(uri)
val date = dateFormatter.getDetailedTimestamp(backupFile.date)
val details =
context.getString(R.string.backup_details, date, backupFile.messages)
newState { copy(selectedBackupDetails = details) }
} catch (e: Exception) {
newState { copy(showSelectedBackupError = true) }
}
}
}
}
@@ -28,6 +28,4 @@ data class BackupState(
val showSelectedBackupError: Boolean = false,
val selectedBackupDetails: String? = null,
val showStopRestoreDialog: Boolean = false,
val upgraded: Boolean = true
)
@@ -135,8 +135,12 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
override val scheduleSelectedIntent: Subject<Long> = PublishSubject.create()
override val changeSimIntent by lazy { binding.sim.clicks() }
override val scheduleCancelIntent by lazy { binding.scheduledCancel.clicks() }
override val sendIntent by lazy { Observable.merge(binding.send.clicks(), binding.scheduledSend.clicks()) }
override val viewQksmsPlusIntent: Subject<Unit> = PublishSubject.create()
override val sendIntent by lazy {
Observable.merge(
binding.send.clicks(),
binding.scheduledSend.clicks()
)
}
override val backPressedIntent: Subject<Unit> = PublishSubject.create()
override val confirmDeleteIntent: Subject<List<Long>> = PublishSubject.create()
override val clearCurrentMessageIntent: Subject<Boolean> = PublishSubject.create()
@@ -727,13 +731,6 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
?.let(binding.messageList::scrollToPosition)
}
override fun showQksmsPlusSnackbar(message: Int) {
Snackbar.make(binding.contentView, message, Snackbar.LENGTH_LONG).run {
setAction(R.string.button_more) { viewQksmsPlusIntent.onNext(Unit) }
setActionTextColor(colors.theme().theme)
show()
}
}
override fun showDeleteDialog(messages: List<Long>) {
val count = messages.size
@@ -70,7 +70,6 @@ interface ComposeView : QkView<ComposeState> {
val scheduleCancelIntent: Observable<*>
val changeSimIntent: Observable<*>
val sendIntent: Observable<Unit>
val viewQksmsPlusIntent: Subject<Unit>
val backPressedIntent: Observable<Unit>
val confirmDeleteIntent: Observable<List<Long>>
val clearCurrentMessageIntent: Subject<Boolean>
@@ -108,8 +107,7 @@ interface ComposeView : QkView<ComposeState> {
fun requestContact()
fun setDraft(draft: String)
fun scrollToMessage(id: Long)
fun showQksmsPlusSnackbar(@StringRes message: Int)
fun showDeleteDialog( messages: List<Long>)
fun showDeleteDialog(messages: List<Long>)
fun showClearCurrentMessageDialog()
fun showReactionsDialog(reactions: List<String>)
fun startSpeechRecognition()
@@ -62,7 +62,6 @@ import dev.octoshrimpy.quik.interactor.SendExistingMessage
import dev.octoshrimpy.quik.interactor.SaveImage
import dev.octoshrimpy.quik.interactor.SendNewMessage
import dev.octoshrimpy.quik.manager.ActiveConversationManager
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.manager.PermissionManager
import dev.octoshrimpy.quik.model.Attachment
import dev.octoshrimpy.quik.model.Conversation
@@ -112,7 +111,6 @@ class ComposeViewModel @Inject constructor(
private val context: Context,
private val activeConversationManager: ActiveConversationManager,
private val addScheduledMessage: AddScheduledMessage,
private val billingManager: BillingManager,
private val actionDelayedMessage: ActionDelayedMessage,
private val conversationRepo: ConversationRepository,
private val deleteMessages: DeleteMessages,
@@ -846,13 +844,9 @@ class ComposeViewModel @Inject constructor(
// Choose a time to schedule the message
view.scheduleIntent
.doOnNext { newState { copy(attaching = false) } }
.withLatestFrom(billingManager.upgradeStatus) { _, upgraded -> upgraded }
.filter { upgraded ->
upgraded.also { if (!upgraded) view.showQksmsPlusSnackbar(R.string.compose_scheduled_plus) }
}
.autoDisposable(view.scope())
.subscribe { view.requestDatePicker() }
.doOnNext { newState { copy(attaching = false) } }
.autoDisposable(view.scope())
.subscribe { view.requestDatePicker() }
view.scheduleAction
.take(1)
@@ -1259,11 +1253,6 @@ class ComposeViewModel @Inject constructor(
.autoDisposable(view.scope())
.subscribe()
// View QKSMS+
view.viewQksmsPlusIntent
.autoDisposable(view.scope())
.subscribe { navigator.showQksmsPlusActivity("compose_schedule") }
// Navigate back
view.optionsItemIntent
.filter { it == android.R.id.home }
@@ -94,7 +94,8 @@ class MainActivity : QkThemedActivity(), MainView {
}
override val homeIntent: Subject<Unit> = PublishSubject.create()
override val navigationIntent: Observable<NavItem> by lazy {
Observable.merge(listOf(
Observable.merge(
listOf(
backPressedSubject,
binding.drawer.inbox.clicks().map { NavItem.INBOX },
binding.drawer.archived.clicks().map { NavItem.ARCHIVED },
@@ -104,12 +105,10 @@ class MainActivity : QkThemedActivity(), MainView {
binding.drawer.messageUtils.clicks().map { NavItem.MESSAGE_UTILS },
binding.drawer.settings.clicks().map { NavItem.SETTINGS },
binding.drawer.about.clicks().map { NavItem.ABOUT },
// plus.clicks().map { NavItem.PLUS },
// help.clicks().map { NavItem.HELP },
binding.drawer.invite.clicks().map { NavItem.INVITE }))
binding.drawer.invite.clicks().map { NavItem.INVITE })
)
}
override val optionsItemIntent: Subject<Int> = PublishSubject.create()
// override val plusBannerIntent by lazy { plusBanner.clicks() }
override val dismissRatingIntent by lazy { binding.drawer.rateDismiss.clicks() }
override val rateIntent by lazy { binding.drawer.rateOkay.clicks() }
override val conversationsSelectedIntent by lazy { conversationsAdapter.selectionChanges }
@@ -187,16 +186,13 @@ class MainActivity : QkThemedActivity(), MainView {
binding.drawer.archivedIcon.imageTintList = tintList
}
// Miscellaneous views
listOf(binding.drawer.plusBadge1, binding.drawer.plusBadge2).forEach { badge ->
badge.setBackgroundTint(theme.theme)
badge.setTextColor(theme.textPrimary)
}
syncingBinding.syncingProgress.progressTintList = ColorStateList.valueOf(theme.theme)
syncingBinding.syncingProgress.indeterminateTintList = ColorStateList.valueOf(theme.theme)
binding.drawer.plusIcon.setTint(theme.theme)
binding.drawer.rateIcon.setTint(theme.theme)
binding.compose.setBackgroundTint(theme.theme)
// Miscellaneous views
syncingBinding.syncingProgress.progressTintList =
ColorStateList.valueOf(theme.theme)
syncingBinding.syncingProgress.indeterminateTintList =
ColorStateList.valueOf(theme.theme)
binding.drawer.rateIcon.setTint(theme.theme)
binding.compose.setBackgroundTint(theme.theme)
// Set the FAB compose icon color
binding.compose.setTint(theme.textPrimary)
@@ -266,11 +262,6 @@ class MainActivity : QkThemedActivity(), MainView {
findItem(R.id.rename)?.isVisible = selectedConversations == 1
}
listOf(binding.drawer.plusBadge1, binding.drawer.plusBadge2).forEach { badge ->
badge.isVisible = drawerBadgesExperiment.variant && !state.upgraded
}
// plus.isVisible = state.upgraded
binding.drawer.plusBanner.isVisible = !state.upgraded
binding.drawer.rateLayout.setVisible(state.showRating)
binding.compose.setVisible(state.page is Inbox || state.page is Archived)
@@ -27,7 +27,6 @@ data class MainState(
val hasError: Boolean = false,
val page: MainPage = Inbox(),
val drawerOpen: Boolean = false,
val upgraded: Boolean = true,
val showRating: Boolean = false,
val syncing: SyncRepository.SyncProgress = SyncRepository.SyncProgress.Idle,
val defaultSms: Boolean = true,
@@ -33,7 +33,6 @@ interface MainView : QkView<MainState> {
val homeIntent: Observable<*>
val navigationIntent: Observable<NavItem>
val optionsItemIntent: Observable<Int>
// val plusBannerIntent: Observable<*>
val dismissRatingIntent: Observable<*>
val rateIntent: Observable<*>
val conversationsSelectedIntent: Observable<List<Long>>
@@ -58,4 +57,4 @@ interface MainView : QkView<MainState> {
fun drawerToggled(opened: Boolean)
}
enum class NavItem { BACK, INBOX, ARCHIVED, BACKUP, SCHEDULED, BLOCKING, MESSAGE_UTILS, SETTINGS, ABOUT, PLUS, HELP, INVITE }
enum class NavItem { BACK, INBOX, ARCHIVED, BACKUP, SCHEDULED, BLOCKING, MESSAGE_UTILS, SETTINGS, ABOUT, INVITE }
@@ -39,7 +39,6 @@ import dev.octoshrimpy.quik.interactor.SpeakThreads
import dev.octoshrimpy.quik.interactor.SyncContacts
import dev.octoshrimpy.quik.interactor.SyncMessages
import dev.octoshrimpy.quik.listener.ContactAddedListener
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.manager.ChangelogManager
import dev.octoshrimpy.quik.manager.PermissionManager
import dev.octoshrimpy.quik.manager.RatingManager
@@ -63,7 +62,6 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject
class MainViewModel @Inject constructor(
billingManager: BillingManager,
contactAddedListener: ContactAddedListener,
markAllSeen: MarkAllSeen,
migratePreferences: MigratePreferences,
@@ -104,13 +102,9 @@ class MainViewModel @Inject constructor(
// Show the syncing UI
disposables += syncRepository.syncProgress
.sample(16, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.subscribe { syncing -> newState { copy(syncing = syncing) } }
// Update the upgraded status
disposables += billingManager.upgradeStatus
.subscribe { upgraded -> newState { copy(upgraded = upgraded) } }
.sample(16, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.subscribe { syncing -> newState { copy(syncing = syncing) } }
// Show the rating UI
disposables += ratingManager.shouldShowRating
@@ -328,42 +322,69 @@ class MainViewModel @Inject constructor(
.subscribe { open -> newState { copy(drawerOpen = open) } }
view.navigationIntent
.withLatestFrom(state) { drawerItem, state ->
newState { copy(drawerOpen = false) }
when (drawerItem) {
NavItem.BACK -> when {
state.drawerOpen -> Unit
state.page is Searching -> view.clearSearch()
state.page is Inbox && state.page.selected > 0 -> view.clearSelection()
state.page is Archived && state.page.selected > 0 -> view.clearSelection()
state.page !is Inbox -> {
newState { copy(page = Inbox(data = conversationRepo.getConversations(prefs.unreadAtTop.get()))) }
.withLatestFrom(state) { drawerItem, state ->
newState { copy(drawerOpen = false) }
when (drawerItem) {
NavItem.BACK -> when {
state.drawerOpen -> Unit
state.page is Searching -> view.clearSearch()
state.page is Inbox && state.page.selected > 0 -> view.clearSelection()
state.page is Archived && state.page.selected > 0 -> view.clearSelection()
state.page !is Inbox -> {
newState {
copy(
page = Inbox(
data = conversationRepo.getConversations(
prefs.unreadAtTop.get()
)
)
)
}
else -> newState { copy(hasError = true) }
}
NavItem.BACKUP -> navigator.showBackup()
NavItem.SCHEDULED -> navigator.showScheduled(null)
NavItem.BLOCKING -> navigator.showBlockedConversations()
NavItem.MESSAGE_UTILS -> navigator.showMessageUtils()
NavItem.SETTINGS -> navigator.showSettings()
NavItem.ABOUT -> navigator.showAbout()
// NavItem.PLUS -> navigator.showQksmsPlusActivity("main_menu")
// NavItem.HELP -> navigator.showSupport()
NavItem.INVITE -> externalNavigator.showInvite()
else -> Unit
else -> newState { copy(hasError = true) }
}
drawerItem
NavItem.BACKUP -> navigator.showBackup()
NavItem.SCHEDULED -> navigator.showScheduled(null)
NavItem.BLOCKING -> navigator.showBlockedConversations()
NavItem.MESSAGE_UTILS -> navigator.showMessageUtils()
NavItem.SETTINGS -> navigator.showSettings()
NavItem.ABOUT -> navigator.showAbout()
NavItem.INVITE -> externalNavigator.showInvite()
else -> Unit
}
.distinctUntilChanged()
.doOnNext { drawerItem ->
when (drawerItem) {
NavItem.INBOX -> newState { copy(page = Inbox(data = conversationRepo.getConversations(prefs.unreadAtTop.get()))) }
NavItem.ARCHIVED -> newState { copy(page = Archived(data = conversationRepo.getConversations(prefs.unreadAtTop.get(), true))) }
else -> Unit
drawerItem
}
.distinctUntilChanged()
.doOnNext { drawerItem ->
when (drawerItem) {
NavItem.INBOX -> newState {
copy(
page = Inbox(
data = conversationRepo.getConversations(
prefs.unreadAtTop.get()
)
)
)
}
NavItem.ARCHIVED -> newState {
copy(
page = Archived(
data = conversationRepo.getConversations(
prefs.unreadAtTop.get(),
true
)
)
)
}
else -> Unit
}
.autoDisposable(view.scope())
.subscribe()
}
.autoDisposable(view.scope())
.subscribe()
view.optionsItemIntent
.filter { itemId -> itemId == R.id.select_all }
@@ -467,13 +488,6 @@ class MainViewModel @Inject constructor(
.autoDisposable(view.scope())
.subscribe { conversation -> view.showRenameDialog(conversation.name) }
// view.plusBannerIntent
// .autoDisposable(view.scope())
// .subscribe {
// newState { copy(drawerOpen = false) }
// navigator.showQksmsPlusActivity("main_banner")
// }
view.rateIntent
.autoDisposable(view.scope())
.subscribe {
@@ -1,128 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.feature.plus
import android.graphics.Typeface
import android.os.Bundle
import androidx.core.view.children
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.jakewharton.rxbinding2.view.clicks
import dagger.android.AndroidInjection
import dev.octoshrimpy.quik.R
import dev.octoshrimpy.quik.common.base.QkThemedActivity
import dev.octoshrimpy.quik.common.util.FontProvider
import dev.octoshrimpy.quik.common.util.extensions.makeToast
import dev.octoshrimpy.quik.common.util.extensions.resolveThemeColor
import dev.octoshrimpy.quik.common.util.extensions.setBackgroundTint
import dev.octoshrimpy.quik.common.util.extensions.setTint
import dev.octoshrimpy.quik.common.util.extensions.setVisible
import dev.octoshrimpy.quik.common.widget.PreferenceView
import dev.octoshrimpy.quik.feature.plus.experiment.UpgradeButtonExperiment
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.databinding.QksmsPlusActivityBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
class PlusActivity : QkThemedActivity(), PlusView {
@Inject lateinit var fontProvider: FontProvider
@Inject lateinit var upgradeButtonExperiment: UpgradeButtonExperiment
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
private val viewModel by lazy { ViewModelProviders.of(this, viewModelFactory)[PlusViewModel::class.java] }
private lateinit var binding: QksmsPlusActivityBinding
override val upgradeIntent get() = binding.upgrade.clicks()
override val upgradeDonateIntent get() = binding.upgradeDonate.clicks()
override val donateIntent get() = binding.donate.clicks()
override val themeClicks get() = binding.themes.clicks()
override val scheduleClicks get() = binding.schedule.clicks()
override val backupClicks get() = binding.backup.clicks()
override val delayedClicks get() = binding.delayed.clicks()
override val nightClicks get() = binding.night.clicks()
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
binding = QksmsPlusActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
setTitle(R.string.title_qksms_plus)
showBackButton(true)
viewModel.bindView(this)
binding.free.setVisible(false)
if (!prefs.systemFont.get()) {
fontProvider.getLato { lato ->
val typeface = Typeface.create(lato, Typeface.BOLD)
binding.toolbarLayout.collapsingToolbar.setCollapsedTitleTypeface(typeface)
binding.toolbarLayout.collapsingToolbar.setExpandedTitleTypeface(typeface)
}
}
// Make the list titles bold
binding.linearLayout.children
.mapNotNull { it as? PreferenceView }
.map { it.titleView }
.forEach { it.setTypeface(it.typeface, Typeface.BOLD) }
val textPrimary = resolveThemeColor(android.R.attr.textColorPrimary)
binding.toolbarLayout.collapsingToolbar.setCollapsedTitleTextColor(textPrimary)
binding.toolbarLayout.collapsingToolbar.setExpandedTitleColor(textPrimary)
val theme = colors.theme().theme
binding.donate.setBackgroundTint(theme)
binding.upgrade.setBackgroundTint(theme)
binding.thanksIcon.setTint(theme)
}
override fun render(state: PlusState) {
binding.description.text = getString(R.string.qksms_plus_description_summary, state.upgradePrice)
binding.upgrade.text = getString(upgradeButtonExperiment.variant, state.upgradePrice, state.currency)
binding.upgradeDonate.text = getString(R.string.qksms_plus_upgrade_donate, state.upgradeDonatePrice, state.currency)
val fdroid = true
binding.free.setVisible(fdroid)
binding.toUpgrade.setVisible(!fdroid && !state.upgraded)
binding.upgraded.setVisible(!fdroid && state.upgraded)
binding.themes.isEnabled = state.upgraded
binding.schedule.isEnabled = state.upgraded
binding.backup.isEnabled = state.upgraded
binding.delayed.isEnabled = state.upgraded
binding.night.isEnabled = state.upgraded
}
override fun initiatePurchaseFlow(billingManager: BillingManager, sku: String) {
GlobalScope.launch(Dispatchers.Main) {
try {
billingManager.initiatePurchaseFlow(this@PlusActivity, sku)
} catch (e: Exception) {
Timber.w(e)
makeToast(R.string.qksms_plus_error)
}
}
}
}
@@ -1,35 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.feature.plus
import androidx.lifecycle.ViewModel
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoMap
import dev.octoshrimpy.quik.injection.ViewModelKey
@Module
class PlusActivityModule {
@Provides
@IntoMap
@ViewModelKey(PlusViewModel::class)
fun providePlusViewModel(viewModel: PlusViewModel): ViewModel = viewModel
}
@@ -1,26 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.feature.plus
data class PlusState(
val upgraded: Boolean = true,
val upgradePrice: String = "",
val upgradeDonatePrice: String = "",
val currency: String = ""
)
@@ -1,38 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.feature.plus
import dev.octoshrimpy.quik.common.base.QkView
import dev.octoshrimpy.quik.manager.BillingManager
import io.reactivex.Observable
interface PlusView : QkView<PlusState> {
val upgradeIntent: Observable<Unit>
val upgradeDonateIntent: Observable<Unit>
val donateIntent: Observable<*>
val themeClicks: Observable<*>
val scheduleClicks: Observable<*>
val backupClicks: Observable<*>
val delayedClicks: Observable<*>
val nightClicks: Observable<*>
fun initiatePurchaseFlow(billingManager: BillingManager, sku: String)
}
@@ -1,84 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.feature.plus
import com.uber.autodispose.android.lifecycle.scope
import com.uber.autodispose.autoDisposable
import dev.octoshrimpy.quik.common.Navigator
import dev.octoshrimpy.quik.common.base.QkViewModel
import dev.octoshrimpy.quik.manager.BillingManager
import io.reactivex.Observable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject
class PlusViewModel @Inject constructor(
private val billingManager: BillingManager,
private val navigator: Navigator
) : QkViewModel<PlusView, PlusState>(PlusState()) {
init {
disposables += billingManager.upgradeStatus
.subscribe { upgraded -> newState { copy(upgraded = upgraded) } }
disposables += billingManager.products
.subscribe { products ->
newState {
val upgrade = products.firstOrNull { it.sku == BillingManager.SKU_PLUS }
val upgradeDonate = products.firstOrNull { it.sku == BillingManager.SKU_PLUS_DONATE }
copy(upgradePrice = upgrade?.price ?: "", upgradeDonatePrice = upgradeDonate?.price ?: "",
currency = upgrade?.priceCurrencyCode ?: upgradeDonate?.priceCurrencyCode ?: "")
}
}
}
override fun bindView(view: PlusView) {
super.bindView(view)
Observable.merge(
view.upgradeIntent.map { BillingManager.SKU_PLUS },
view.upgradeDonateIntent.map { BillingManager.SKU_PLUS_DONATE })
.autoDisposable(view.scope())
.subscribe { sku -> view.initiatePurchaseFlow(billingManager, sku) }
// view.donateIntent
// .autoDisposable(view.scope())
// .subscribe { navigator.showDonation() }
view.themeClicks
.autoDisposable(view.scope())
.subscribe { navigator.showSettings() }
view.scheduleClicks
.autoDisposable(view.scope())
.subscribe { navigator.showScheduled(null) }
view.backupClicks
.autoDisposable(view.scope())
.subscribe { navigator.showBackup() }
view.delayedClicks
.autoDisposable(view.scope())
.subscribe { navigator.showSettings() }
view.nightClicks
.autoDisposable(view.scope())
.subscribe { navigator.showSettings() }
}
}
@@ -1,41 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package dev.octoshrimpy.quik.feature.plus.experiment
import android.content.Context
import dev.octoshrimpy.quik.R
import dev.octoshrimpy.quik.experiment.Experiment
import dev.octoshrimpy.quik.experiment.Variant
import javax.inject.Inject
class UpgradeButtonExperiment @Inject constructor(
context: Context,
) : Experiment<Int>(context) {
override val key: String = "Upgrade Button"
override val variants: List<Variant<Int>> = listOf(
Variant("variant_a", R.string.qksms_plus_upgrade),
Variant("variant_b", R.string.qksms_plus_upgrade_b),
Variant("variant_c", R.string.qksms_plus_upgrade_c),
Variant("variant_d", R.string.qksms_plus_upgrade_d))
override val default: Int = R.string.qksms_plus_upgrade
}
@@ -41,11 +41,12 @@ class ScheduledActivity : QkThemedActivity(), ScheduledView {
private lateinit var binding: ScheduledActivityBinding
@Inject lateinit var scheduledMessageAdapter: ScheduledMessageAdapter
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
@Inject
lateinit var scheduledMessageAdapter: ScheduledMessageAdapter
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override val composeIntent by lazy { binding.compose.clicks() }
override val upgradeIntent by lazy { binding.upgrade.clicks() }
override val messagesSelectedIntent by lazy { scheduledMessageAdapter.selectionChanges }
override val optionsItemIntent: Subject<Int> = PublishSubject.create()
override val deleteScheduledMessages: Subject<List<Long>> = PublishSubject.create()
@@ -74,20 +75,20 @@ class ScheduledActivity : QkThemedActivity(), ScheduledView {
binding.sampleMessage.setTextColor(theme.textPrimary)
binding.compose.setTint(theme.textPrimary)
binding.compose.setBackgroundTint(theme.theme)
binding.upgrade.setBackgroundTint(theme.theme)
binding.upgradeIcon.setTint(theme.textPrimary)
binding.upgradeLabel.setTextColor(theme.textPrimary)
}
}
override fun render(state: ScheduledState) {
scheduledMessageAdapter.updateData(state.scheduledMessages)
setTitle(when {
(state.selectedMessages > 0) ->
getString(R.string.compose_title_selected, state.selectedMessages)
else -> getString(R.string.scheduled_title)
})
setTitle(
when {
(state.selectedMessages > 0) ->
getString(R.string.compose_title_selected, state.selectedMessages)
else -> getString(R.string.scheduled_title)
}
)
// show/hide menu items
toolbar?.menu?.findItem(R.id.select_all)?.isVisible =
@@ -102,8 +103,7 @@ class ScheduledActivity : QkThemedActivity(), ScheduledView {
((scheduledMessageAdapter.itemCount != 0) && (state.selectedMessages == 1))
// show compose button
binding.compose.isVisible = state.upgraded && (state.conversationId == null)
binding.upgrade.isVisible = !state.upgraded
binding.compose.isVisible = state.conversationId == null
}
override fun onBackPressed() = backPressedIntent.onNext(Unit)
@@ -117,7 +117,11 @@ class ScheduledActivity : QkThemedActivity(), ScheduledView {
AlertDialog.Builder(this)
.setTitle(R.string.dialog_delete_title)
.setMessage(resources.getQuantityString(R.plurals.dialog_delete_chat, count, count))
.setPositiveButton(R.string.button_delete) { _, _ -> deleteScheduledMessages.onNext(messages) }
.setPositiveButton(R.string.button_delete) { _, _ ->
deleteScheduledMessages.onNext(
messages
)
}
.setNegativeButton(R.string.button_cancel, null)
.show()
}
@@ -127,7 +131,11 @@ class ScheduledActivity : QkThemedActivity(), ScheduledView {
AlertDialog.Builder(this)
.setTitle(R.string.main_menu_send_now)
.setMessage(resources.getQuantityString(R.plurals.dialog_send_now, count, count))
.setPositiveButton(R.string.main_menu_send_now) { _, _ -> sendScheduledMessages.onNext(messages) }
.setPositiveButton(R.string.main_menu_send_now) { _, _ ->
sendScheduledMessages.onNext(
messages
)
}
.setNegativeButton(R.string.button_cancel, null)
.show()
}
@@ -23,7 +23,6 @@ import io.realm.RealmResults
data class ScheduledState(
val scheduledMessages: RealmResults<ScheduledMessage>? = null,
val upgraded: Boolean = true,
val selectedMessages: Int = 0,
val conversationId: Long? = null,
)
@@ -24,7 +24,6 @@ import io.reactivex.Observable
interface ScheduledView : QkView<ScheduledState> {
val composeIntent: Observable<*>
val upgradeIntent: Observable<*>
val messagesSelectedIntent: Observable<List<Long>>
val optionsItemIntent: Observable<Int>
val deleteScheduledMessages: Observable<List<Long>>
@@ -9,7 +9,6 @@ import dev.octoshrimpy.quik.common.base.QkViewModel
import dev.octoshrimpy.quik.common.util.ClipboardUtils
import dev.octoshrimpy.quik.interactor.DeleteScheduledMessages
import dev.octoshrimpy.quik.interactor.SendScheduledMessage
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.repository.ScheduledMessageRepository
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.rxkotlin.plusAssign
@@ -19,7 +18,6 @@ import javax.inject.Named
class ScheduledViewModel @Inject constructor(
@Named("conversationId") private val conversationId: Long?,
billingManager: BillingManager,
private val context: Context,
private val navigator: Navigator,
private val scheduledMessageRepo: ScheduledMessageRepository,
@@ -32,8 +30,6 @@ class ScheduledViewModel @Inject constructor(
init {
loadMessages(conversationId)
disposables += billingManager.upgradeStatus
.subscribe { upgraded -> newState { copy(upgraded = upgraded) } }
}
override fun bindView(view: ScheduledView) {
@@ -159,10 +155,6 @@ class ScheduledViewModel @Inject constructor(
navigator.showCompose(mode = "scheduling")
view.clearSelection()
}
view.upgradeIntent
.autoDisposable(view.scope())
.subscribe { navigator.showQksmsPlusActivity("schedule_fab") }
}
private fun loadMessages(conversationId: Long?) {
@@ -76,7 +76,6 @@ class SettingsController : QkController<SettingsControllerBinding, SettingsView,
TextInputDialog(activity!!, context.getString(R.string.settings_signature_title), signatureSubject::onNext)
}
private val viewQksmsPlusSubject: Subject<Unit> = PublishSubject.create()
private val startTimeSelectedSubject: Subject<Pair<Int, Int>> = PublishSubject.create()
private val endTimeSelectedSubject: Subject<Pair<Int, Int>> = PublishSubject.create()
private val signatureSubject: Subject<String> = PublishSubject.create()
@@ -124,8 +123,6 @@ class SettingsController : QkController<SettingsControllerBinding, SettingsView,
override fun aboutLongClicks(): Observable<*> = binding.about.longClicks()
override fun viewQksmsPlusClicks(): Observable<*> = viewQksmsPlusSubject
override fun nightModeSelected(): Observable<Int> = nightModeDialog.adapter.menuItemClicks
override fun nightStartSelected(): Observable<Pair<Int, Int>> = startTimeSelectedSubject
@@ -207,16 +204,6 @@ class SettingsController : QkController<SettingsControllerBinding, SettingsView,
}
}
override fun showQksmsPlusSnackbar() {
view?.run {
Snackbar.make(binding.contentView, R.string.toast_qksms_plus, Snackbar.LENGTH_LONG).run {
setAction(R.string.button_more) { viewQksmsPlusSubject.onNext(Unit) }
setActionTextColor(colors.theme().theme)
show()
}
}
}
// TODO change this to a PopupWindow
override fun showNightModeDialog() = nightModeDialog.show(activity!!)
@@ -29,7 +29,6 @@ import dev.octoshrimpy.quik.common.util.Colors
import dev.octoshrimpy.quik.common.util.DateFormatter
import dev.octoshrimpy.quik.common.util.extensions.makeToast
import dev.octoshrimpy.quik.interactor.SyncMessages
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.repository.SyncRepository
import dev.octoshrimpy.quik.util.NightModeManager
import dev.octoshrimpy.quik.util.Preferences
@@ -43,7 +42,6 @@ class SettingsPresenter @Inject constructor(
colors: Colors,
syncRepo: SyncRepository,
private val context: Context,
private val billingManager: BillingManager,
private val dateFormatter: DateFormatter,
private val navigator: Navigator,
private val externalNavigator: ExternalNavigator,
@@ -236,19 +234,8 @@ class SettingsPresenter @Inject constructor(
}
view.nightModeSelected()
.withLatestFrom(billingManager.upgradeStatus) { mode, upgraded ->
// if (!upgraded && mode == Preferences.NIGHT_MODE_AUTO) {
// view.showQksmsPlusSnackbar()
// } else {
nightModeManager.updateNightMode(mode)
// }
}
.autoDisposable(view.scope())
.subscribe()
view.viewQksmsPlusClicks()
.autoDisposable(view.scope())
.subscribe { navigator.showQksmsPlusActivity("settings_night") }
.autoDisposable(view.scope())
.subscribe { nightModeManager.updateNightMode(it) }
view.nightStartSelected()
.autoDisposable(view.scope())
@@ -263,15 +250,8 @@ class SettingsPresenter @Inject constructor(
.subscribe(prefs.textSize::set)
view.sendDelaySelected()
.withLatestFrom(billingManager.upgradeStatus) { duration, upgraded ->
// if (!upgraded && duration != 0) {
// view.showQksmsPlusSnackbar()
// } else {
prefs.sendDelay.set(duration)
// }
}
.autoDisposable(view.scope())
.subscribe()
.autoDisposable(view.scope())
.subscribe { prefs.sendDelay.set(it) }
view.signatureChanged()
.doOnNext(prefs.signature::set)
@@ -25,7 +25,6 @@ import io.reactivex.Observable
interface SettingsView : QkViewContract<SettingsState> {
fun preferenceClicks(): Observable<PreferenceView>
fun aboutLongClicks(): Observable<*>
fun viewQksmsPlusClicks(): Observable<*>
fun nightModeSelected(): Observable<Int>
fun nightStartSelected(): Observable<Pair<Int, Int>>
fun nightEndSelected(): Observable<Pair<Int, Int>>
@@ -35,7 +34,6 @@ interface SettingsView : QkViewContract<SettingsState> {
fun mmsSizeSelected(): Observable<Int>
fun messageLinkHandlingSelected(): Observable<Int>
fun showQksmsPlusSnackbar()
fun showNightModeDialog()
fun showStartTimePicker(hour: Int, minute: Int)
fun showEndTimePicker(hour: Int, minute: Int)
@@ -48,11 +48,13 @@ class ThemePickerController(
@Inject override lateinit var presenter: ThemePickerPresenter
@Inject lateinit var colors: Colors
@Inject lateinit var themeAdapter: ThemeAdapter
@Inject lateinit var themePagerAdapter: ThemePagerAdapter
@Inject
lateinit var colors: Colors
private val viewQksmsPlusSubject: Subject<Unit> = PublishSubject.create()
@Inject
lateinit var themeAdapter: ThemeAdapter
@Inject
lateinit var themePagerAdapter: ThemePagerAdapter
init {
appComponent
@@ -92,14 +94,6 @@ class ThemePickerController(
}
}
override fun showQksmsPlusSnackbar() {
Snackbar.make(binding.contentView, R.string.toast_qksms_plus, Snackbar.LENGTH_LONG).run {
setAction(R.string.button_more) { viewQksmsPlusSubject.onNext(Unit) }
setActionTextColor(colors.theme().theme)
show()
}
}
override fun themeSelected(): Observable<Int> = themeAdapter.colorSelected
override fun hsvThemeSelected(): Observable<Int> = binding.hsvPicker.picker.selectedColor
@@ -108,8 +102,6 @@ class ThemePickerController(
override fun applyHsvThemeClicks(): Observable<*> = binding.hsvPicker.apply.clicks()
override fun viewQksmsPlusClicks(): Observable<*> = viewQksmsPlusSubject
override fun render(state: ThemePickerState) {
binding.tabs.setRecipientId(state.recipientId)
@@ -24,7 +24,6 @@ import com.uber.autodispose.autoDisposable
import dev.octoshrimpy.quik.common.Navigator
import dev.octoshrimpy.quik.common.base.QkPresenter
import dev.octoshrimpy.quik.common.util.Colors
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.manager.WidgetManager
import dev.octoshrimpy.quik.util.Preferences
import io.reactivex.rxkotlin.Observables
@@ -34,7 +33,6 @@ import javax.inject.Named
class ThemePickerPresenter @Inject constructor(
prefs: Preferences,
@Named("recipientId") private val recipientId: Long,
private val billingManager: BillingManager,
private val colors: Colors,
private val navigator: Navigator,
private val widgetManager: WidgetManager
@@ -74,24 +72,14 @@ class ThemePickerPresenter @Inject constructor(
// Update the theme, when apply is clicked
view.applyHsvThemeClicks()
.withLatestFrom(view.hsvThemeSelected()) { _, color -> color }
.withLatestFrom(billingManager.upgradeStatus) { color, upgraded ->
if (!upgraded) {
view.showQksmsPlusSnackbar()
} else {
theme.set(color)
if (recipientId == 0L) {
widgetManager.updateTheme()
}
}
.withLatestFrom(view.hsvThemeSelected()) { _, color ->
theme.set(color)
if (recipientId == 0L) {
widgetManager.updateTheme()
}
.autoDisposable(view.scope())
.subscribe()
// Show QKSMS+ activity
view.viewQksmsPlusClicks()
.autoDisposable(view.scope())
.subscribe { navigator.showQksmsPlusActivity("settings_theme") }
}
.autoDisposable(view.scope())
.subscribe()
// Reset the theme
view.clearHsvThemeClicks()
@@ -27,9 +27,7 @@ interface ThemePickerView : QkViewContract<ThemePickerState> {
fun hsvThemeSelected(): Observable<Int>
fun clearHsvThemeClicks(): Observable<*>
fun applyHsvThemeClicks(): Observable<*>
fun viewQksmsPlusClicks(): Observable<*>
fun setCurrentTheme(color: Int)
fun showQksmsPlusSnackbar()
}
@@ -33,7 +33,6 @@ import dagger.Provides
import dev.octoshrimpy.quik.blocking.BlockingClient
import dev.octoshrimpy.quik.blocking.BlockingManager
import dev.octoshrimpy.quik.common.ViewModelFactory
import dev.octoshrimpy.quik.common.util.BillingManagerImpl
import dev.octoshrimpy.quik.common.util.NotificationManagerImpl
import dev.octoshrimpy.quik.common.util.ShortcutManagerImpl
import dev.octoshrimpy.quik.feature.conversationinfo.injection.ConversationInfoComponent
@@ -44,7 +43,6 @@ import dev.octoshrimpy.quik.manager.ActiveConversationManager
import dev.octoshrimpy.quik.manager.ActiveConversationManagerImpl
import dev.octoshrimpy.quik.manager.AlarmManager
import dev.octoshrimpy.quik.manager.AlarmManagerImpl
import dev.octoshrimpy.quik.manager.BillingManager
import dev.octoshrimpy.quik.manager.ChangelogManager
import dev.octoshrimpy.quik.manager.ChangelogManagerImpl
import dev.octoshrimpy.quik.manager.KeyManager
@@ -137,10 +135,8 @@ class AppModule(private var application: Application) {
// Manager
@Provides
fun provideBillingManager(manager: BillingManagerImpl): BillingManager = manager
@Provides
fun provideActiveConversationManager(manager: ActiveConversationManagerImpl): ActiveConversationManager = manager
fun provideActiveConversationManager(manager: ActiveConversationManagerImpl): ActiveConversationManager =
manager
@Provides
fun provideAlarmManager(manager: AlarmManagerImpl): AlarmManager = manager
@@ -34,8 +34,6 @@ import dev.octoshrimpy.quik.feature.main.MainActivityModule
import dev.octoshrimpy.quik.feature.messageutils.MessageUtilsActivity
import dev.octoshrimpy.quik.feature.notificationprefs.NotificationPrefsActivity
import dev.octoshrimpy.quik.feature.notificationprefs.NotificationPrefsActivityModule
import dev.octoshrimpy.quik.feature.plus.PlusActivity
import dev.octoshrimpy.quik.feature.plus.PlusActivityModule
import dev.octoshrimpy.quik.feature.qkreply.QkReplyActivity
import dev.octoshrimpy.quik.feature.qkreply.QkReplyActivityModule
import dev.octoshrimpy.quik.feature.scheduled.ScheduledActivity
@@ -51,10 +49,6 @@ abstract class ActivityBuilderModule {
@ContributesAndroidInjector(modules = [MainActivityModule::class])
abstract fun bindMainActivity(): MainActivity
@ActivityScope
@ContributesAndroidInjector(modules = [PlusActivityModule::class])
abstract fun bindPlusActivity(): PlusActivity
@ActivityScope
@ContributesAndroidInjector(modules = [])
abstract fun bindBackupActivity(): BackupActivity
@@ -167,7 +167,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:src="@drawable/ic_star_black_24dp"
android:src="@drawable/ic_file_upload_black_24dp"
tools:tint="@color/textPrimaryDark" />
<dev.octoshrimpy.quik.common.widget.QkTextView
@@ -176,7 +176,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/title_qksms_plus"
android:text="@string/backup_now"
android:textColor="@color/textPrimaryDark"
android:textStyle="bold"
app:textSize="primary" />
@@ -83,18 +83,6 @@
style="@style/DrawerText"
android:text="@string/backup_title" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/plusBadge1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_rectangle_2dp"
android:padding="4dp"
android:text="@string/title_qksms_plus"
android:textStyle="bold"
app:textSize="tertiary"
tools:backgroundTint="@color/tools_theme"
tools:textColor="@color/textPrimaryDark" />
</LinearLayout>
<LinearLayout
@@ -110,18 +98,6 @@
style="@style/DrawerText"
android:text="@string/drawer_scheduled" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/plusBadge2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_rectangle_2dp"
android:padding="4dp"
android:text="@string/title_qksms_plus"
android:textStyle="bold"
app:textSize="tertiary"
tools:backgroundTint="@color/tools_theme"
tools:textColor="@color/textPrimaryDark" />
</LinearLayout>
<LinearLayout
@@ -191,36 +167,6 @@
</LinearLayout>
<!-- <LinearLayout-->
<!-- android:id="@+id/plus"-->
<!-- style="@style/DrawerRow">-->
<!-- <ImageView-->
<!-- style="@style/DrawerIcon"-->
<!-- android:src="@drawable/ic_star_black_24dp"-->
<!-- android:tint="?android:attr/textColorSecondary" />-->
<!-- <dev.octoshrimpy.quik.common.widget.QkTextView-->
<!-- style="@style/DrawerText"-->
<!-- android:text="@string/drawer_plus" />-->
<!-- </LinearLayout>-->
<!-- <LinearLayout-->
<!-- android:id="@+id/help"-->
<!-- style="@style/DrawerRow">-->
<!-- <ImageView-->
<!-- style="@style/DrawerIcon"-->
<!-- android:src="@drawable/ic_help_black_24dp"-->
<!-- android:tint="?android:attr/textColorSecondary" />-->
<!-- <dev.octoshrimpy.quik.common.widget.QkTextView-->
<!-- style="@style/DrawerText"-->
<!-- android:text="@string/drawer_help" />-->
<!-- </LinearLayout>-->
<LinearLayout
android:id="@+id/invite"
style="@style/DrawerRow">
@@ -236,66 +182,6 @@
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/plusBanner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@drawable/rounded_rectangle_outline_2dp"
android:backgroundTint="?android:attr/divider"
android:foreground="?attr/selectableItemBackground"
android:padding="16dp">
<ImageView
android:id="@+id/plusIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_star_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:tint="@color/tools_theme" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/plusTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/drawer_plus_banner_title"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/plusNext"
app:layout_constraintStart_toEndOf="@id/plusIcon"
app:layout_constraintTop_toTopOf="parent"
app:textSize="primary" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/plusSummary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="@string/drawer_plus_banner_summary"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@id/plusTitle"
app:layout_constraintStart_toStartOf="@id/plusTitle"
app:layout_constraintTop_toBottomOf="@id/plusTitle"
app:textSize="secondary" />
<ImageView
android:id="@+id/plusNext"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_chevron_right_black_24dp"
app:tint="?android:attr/textColorTertiary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/rateLayout"
android:layout_width="match_parent"
@@ -1,267 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 Moez Bhatti <moez.bhatti@gmail.com>
~
~ 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 <http://www.gnu.org/licenses/>.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbarLayout"
layout="@layout/collapsing_toolbar" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="8dp">
<LinearLayout
android:id="@+id/toUpgrade"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
android:orientation="vertical">
<dev.octoshrimpy.quik.common.widget.QkTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/qksms_plus_description_title"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:textSize="primary" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/qksms_plus_description_summary"
android:textColor="?android:attr/textColorSecondary"
app:textSize="secondary" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/upgrade"
style="@style/TextButton"
android:layout_marginTop="16dp"
android:background="@drawable/rounded_rectangle_2dp"
android:text="@string/qksms_plus_upgrade"
app:textColor="primaryOnTheme"
tools:backgroundTint="@color/tools_theme" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/upgradeDonate"
style="@style/TextButton"
android:layout_marginTop="8dp"
android:background="@drawable/rounded_rectangle_outline_2dp"
android:backgroundTint="?android:attr/divider"
android:text="@string/qksms_plus_upgrade_donate"
android:textColor="?android:attr/textColorPrimary"
tools:backgroundTint="@color/separatorLight" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/upgraded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:background="@drawable/rounded_rectangle_2dp"
android:backgroundTint="?android:attr/divider"
android:padding="16dp"
tools:backgroundTint="@color/separatorLight">
<ImageView
android:id="@+id/thanksIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_favorite_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:tint="@color/tools_theme" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/thanksTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="@string/qksms_plus_thanks_title"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/thanksIcon"
app:textSize="secondary" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/qksms_plus_thanks_summary"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="@id/thanksTitle"
app:layout_constraintStart_toStartOf="@id/thanksTitle"
app:layout_constraintTop_toBottomOf="@id/thanksTitle"
app:textSize="secondary" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/free"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="24dp"
android:orientation="vertical">
<dev.octoshrimpy.quik.common.widget.QkTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/qksms_plus_free_title"
android:textColor="?android:attr/textColorSecondary"
app:textSize="secondary" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/donate"
style="@style/TextButton"
android:layout_marginTop="16dp"
android:background="@drawable/rounded_rectangle_2dp"
android:text="@string/qksms_plus_donate"
app:textColor="primaryOnTheme"
tools:backgroundTint="@color/tools_theme" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="8dp"
android:background="?android:attr/divider" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:id="@+id/themes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_palette_black_24dp"
app:summary="@string/qksms_plus_themes_summary"
app:title="@string/qksms_plus_themes_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:id="@+id/schedule"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_event_black_24dp"
app:summary="@string/qksms_plus_scheduled_summary"
app:title="@string/qksms_plus_scheduled_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:id="@+id/backup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_backup_black_24dp"
app:summary="@string/qksms_plus_backup_summary"
app:title="@string/qksms_plus_backup_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:id="@+id/delayed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_av_timer_black_24dp"
app:summary="@string/qksms_plus_delayed_summary"
app:title="@string/qksms_plus_delayed_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:id="@+id/night"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_invert_colors_black_24dp"
app:summary="@string/qksms_plus_night_summary"
app:title="@string/qksms_plus_night_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_more_horiz_black_24dp"
app:summary="@string/qksms_plus_more_summary"
app:title="@string/qksms_plus_more_title" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="24dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="8dp"
android:text="@string/qksms_plus_coming_soon"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:textSize="primary" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.25"
app:icon="@drawable/ic_favorite_black_24dp"
app:summary="@string/qksms_plus_emoji_summary"
app:title="@string/qksms_plus_emoji_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.25"
app:icon="@drawable/ic_block_white_24dp"
app:summary="@string/qksms_plus_blacklist_summary"
app:title="@string/qksms_plus_blacklist_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.25"
app:icon="@drawable/ic_forward_black_24dp"
app:summary="@string/qksms_plus_forward_summary"
app:title="@string/qksms_plus_forward_title" />
<dev.octoshrimpy.quik.common.widget.PreferenceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.25"
app:icon="@drawable/ic_reply_white_24dp"
app:summary="@string/qksms_plus_respond_summary"
app:title="@string/qksms_plus_respond_title" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="?android:attr/divider" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -150,39 +150,6 @@
android:visibility="visible"
tools:backgroundTint="@color/tools_theme" />
<LinearLayout
android:id="@+id/upgrade"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:background="@drawable/rounded_rectangle_24dp"
android:elevation="4dp"
android:gravity="center"
android:visibility="gone"
tools:backgroundTint="@color/tools_theme">
<ImageView
android:id="@+id/upgradeIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:src="@drawable/ic_star_black_24dp"
tools:tint="@color/textPrimaryDark" />
<dev.octoshrimpy.quik.common.widget.QkTextView
android:id="@+id/upgradeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="@string/title_qksms_plus"
android:textColor="@color/textPrimaryDark"
android:textStyle="bold"
app:textSize="primary" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"