diff --git a/data/src/main/java/manager/ExternalBlockingManagerImpl.kt b/data/src/main/java/manager/ExternalBlockingManagerImpl.kt index 48c18e1e..57c86ac5 100644 --- a/data/src/main/java/manager/ExternalBlockingManagerImpl.kt +++ b/data/src/main/java/manager/ExternalBlockingManagerImpl.kt @@ -30,10 +30,14 @@ import androidx.os.bundleOf import io.reactivex.Single import io.reactivex.subjects.SingleSubject import timber.log.Timber +import util.Preferences import util.tryOrNull import javax.inject.Inject -class ExternalBlockingManagerImpl @Inject constructor(private val context: Context) : ExternalBlockingManager { +class ExternalBlockingManagerImpl @Inject constructor( + private val context: Context, + private val prefs: Preferences +) : ExternalBlockingManager { companion object { const val RATING_UNKNOWN = 0 @@ -48,23 +52,33 @@ class ExternalBlockingManagerImpl @Inject constructor(private val context: Conte * Return a Single which emits whether or not the given [address] should be blocked */ override fun shouldBlock(address: String): Single { - return Binder(context, address).shouldBlock() + return Binder(context, prefs, address).shouldBlock() } - private class Binder(private val context: Context, private val address: String) : ServiceConnection { + private class Binder( + private val context: Context, + private val prefs: Preferences, + private val address: String + ) : ServiceConnection { private val subject: SingleSubject = SingleSubject.create() private var serviceMessenger: Messenger? = null private var isBound: Boolean = false fun shouldBlock(): Single { - // If either version of Should I Answer? is installed, build the intent to request a rating - val intent = tryOrNull { - context.packageManager.getApplicationInfo("org.mistergroup.shouldianswerpersonal", 0).enabled - Intent("org.mistergroup.shouldianswerpersonal.PublicService").setPackage("org.mistergroup.shouldianswerpersonal") - } ?: tryOrNull { - context.packageManager.getApplicationInfo("org.mistergroup.muzutozvednout", 0).enabled - Intent("org.mistergroup.muzutozvednout.PublicService").setPackage("org.mistergroup.muzutozvednout") + + var intent: Intent? = null + + // If either version of Should I Answer? is installed and SIA is enabled, build the + // intent to request a rating + if (prefs.sia.get()) { + intent = tryOrNull { + context.packageManager.getApplicationInfo("org.mistergroup.shouldianswerpersonal", 0).enabled + Intent("org.mistergroup.shouldianswerpersonal.PublicService").setPackage("org.mistergroup.shouldianswerpersonal") + } ?: tryOrNull { + context.packageManager.getApplicationInfo("org.mistergroup.muzutozvednout", 0).enabled + Intent("org.mistergroup.muzutozvednout.PublicService").setPackage("org.mistergroup.muzutozvednout") + } } // If the intent isn't null, bind the service and wait for a result. Otherwise, don't block diff --git a/data/src/main/java/repository/MessageRepositoryImpl.kt b/data/src/main/java/repository/MessageRepositoryImpl.kt index 666379c7..1391e063 100644 --- a/data/src/main/java/repository/MessageRepositoryImpl.kt +++ b/data/src/main/java/repository/MessageRepositoryImpl.kt @@ -91,14 +91,11 @@ class MessageRepositoryImpl @Inject constructor( .findAll()) } - override fun getBlockedConversations(): Flowable> { + override fun getBlockedConversations(): RealmResults { return Realm.getDefaultInstance() .where(Conversation::class.java) .equalTo("blocked", true) .findAllAsync() - .asFlowable() - .filter { it.isLoaded } - .map { it.toList() } } override fun getConversationAsync(threadId: Long): Conversation { diff --git a/data/src/main/java/util/Preferences.kt b/data/src/main/java/util/Preferences.kt index 1475e7a9..e6eabe85 100644 --- a/data/src/main/java/util/Preferences.kt +++ b/data/src/main/java/util/Preferences.kt @@ -45,6 +45,7 @@ class Preferences @Inject constructor(private val rxPrefs: RxSharedPreferences) val nightStart = rxPrefs.getString("nightStart", "6:00 PM") val nightEnd = rxPrefs.getString("nightEnd", "6:00 AM") val black = rxPrefs.getBoolean("black", false) + val sia = rxPrefs.getBoolean("sia", false) val autoEmoji = rxPrefs.getBoolean("autoEmoji", true) val delivery = rxPrefs.getBoolean("delivery", false) val textSize = rxPrefs.getInteger("textSize", TEXT_SIZE_NORMAL) diff --git a/domain/src/main/java/repository/MessageRepository.kt b/domain/src/main/java/repository/MessageRepository.kt index 928f95ef..b732b290 100644 --- a/domain/src/main/java/repository/MessageRepository.kt +++ b/domain/src/main/java/repository/MessageRepository.kt @@ -31,7 +31,7 @@ interface MessageRepository { fun getConversationsSnapshot(): List - fun getBlockedConversations(): Flowable> + fun getBlockedConversations(): RealmResults fun getConversationAsync(threadId: Long): Conversation diff --git a/presentation/src/main/java/common/Navigator.kt b/presentation/src/main/java/common/Navigator.kt index cbecbbc6..3c04d7c5 100644 --- a/presentation/src/main/java/common/Navigator.kt +++ b/presentation/src/main/java/common/Navigator.kt @@ -145,6 +145,15 @@ class Navigator @Inject constructor(private val context: Context, private val no startActivityExternal(intent) } + /** + * Launch the Play Store and display the Should I Answer? listing + */ + fun showSia() { + val url = "https://play.google.com/store/apps/details?id=org.mistergroup.shouldianswerpersonal" + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + startActivity(intent) + } + fun showSupport() { val intent = Intent(Intent.ACTION_SENDTO) intent.data = Uri.parse("mailto:") diff --git a/presentation/src/main/java/feature/blocked/BlockedActivity.kt b/presentation/src/main/java/feature/blocked/BlockedActivity.kt index 8f806e37..5619b8b9 100644 --- a/presentation/src/main/java/feature/blocked/BlockedActivity.kt +++ b/presentation/src/main/java/feature/blocked/BlockedActivity.kt @@ -20,15 +20,16 @@ package feature.blocked import android.app.AlertDialog import android.os.Bundle +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 common.base.QkThemedActivity import injection.appComponent -import common.util.extensions.setVisible import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.Subject import kotlinx.android.synthetic.main.blocked_activity.* -import common.base.QkThemedActivity +import kotlinx.android.synthetic.main.settings_switch_widget.view.* import javax.inject.Inject class BlockedActivity : QkThemedActivity(), BlockedView { @@ -36,6 +37,7 @@ class BlockedActivity : QkThemedActivity(), BlockedView { @Inject lateinit var blockedAdapter: BlockedAdapter override val viewModelClass = BlockedViewModel::class + override val siaClickedIntent by lazy { shouldIAnswer.clicks() } override val unblockIntent by lazy { blockedAdapter.unblock } override val confirmUnblockIntent: Subject = PublishSubject.create() @@ -54,12 +56,14 @@ class BlockedActivity : QkThemedActivity(), BlockedView { .autoDisposable(scope()) .subscribe { color -> window.decorView.setBackgroundColor(color) } + blockedAdapter.emptyView = empty conversations.adapter = blockedAdapter } override fun render(state: BlockedState) { - blockedAdapter.flowable = state.data - empty.setVisible(state.empty) + shouldIAnswer.checkbox.isChecked = state.siaEnabled + + blockedAdapter.updateData(state.data) } override fun showUnblockDialog() { diff --git a/presentation/src/main/java/feature/blocked/BlockedAdapter.kt b/presentation/src/main/java/feature/blocked/BlockedAdapter.kt index 2fc6a76a..93856153 100644 --- a/presentation/src/main/java/feature/blocked/BlockedAdapter.kt +++ b/presentation/src/main/java/feature/blocked/BlockedAdapter.kt @@ -22,16 +22,16 @@ import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup import com.moez.QKSMS.R +import common.base.QkRealmAdapter +import common.base.QkViewHolder import io.reactivex.subjects.PublishSubject import kotlinx.android.synthetic.main.blocked_list_item.view.* import model.Contact import model.Conversation import model.PhoneNumber -import common.base.FlowableAdapter -import common.base.QkViewHolder import javax.inject.Inject -class BlockedAdapter @Inject constructor(private val context: Context) : FlowableAdapter() { +class BlockedAdapter @Inject constructor(private val context: Context) : QkRealmAdapter() { val unblock: PublishSubject = PublishSubject.create() @@ -40,7 +40,7 @@ class BlockedAdapter @Inject constructor(private val context: Context) : Flowabl } override fun onBindViewHolder(holder: QkViewHolder, position: Int) { - val conversation = getItem(position) + val conversation = getItem(position)!! val view = holder.itemView view.setOnClickListener { unblock.onNext(conversation.id) } diff --git a/presentation/src/main/java/feature/blocked/BlockedState.kt b/presentation/src/main/java/feature/blocked/BlockedState.kt index f7ca41cd..41fae68e 100644 --- a/presentation/src/main/java/feature/blocked/BlockedState.kt +++ b/presentation/src/main/java/feature/blocked/BlockedState.kt @@ -18,10 +18,10 @@ */ package feature.blocked -import io.reactivex.Flowable +import io.realm.RealmResults import model.Conversation data class BlockedState( - val data: Flowable>? = null, - val empty: Boolean = false + val siaEnabled: Boolean = false, + val data: RealmResults? = null ) \ No newline at end of file diff --git a/presentation/src/main/java/feature/blocked/BlockedView.kt b/presentation/src/main/java/feature/blocked/BlockedView.kt index 17f422fe..0f5c1561 100644 --- a/presentation/src/main/java/feature/blocked/BlockedView.kt +++ b/presentation/src/main/java/feature/blocked/BlockedView.kt @@ -18,13 +18,14 @@ */ package feature.blocked -import io.reactivex.Observable import common.base.QkView +import io.reactivex.Observable interface BlockedView : QkView { + val siaClickedIntent: Observable<*> val unblockIntent: Observable - val confirmUnblockIntent: Observable + val confirmUnblockIntent: Observable<*> fun showUnblockDialog() diff --git a/presentation/src/main/java/feature/blocked/BlockedViewModel.kt b/presentation/src/main/java/feature/blocked/BlockedViewModel.kt index 925b7f2d..cd3f6f04 100644 --- a/presentation/src/main/java/feature/blocked/BlockedViewModel.kt +++ b/presentation/src/main/java/feature/blocked/BlockedViewModel.kt @@ -18,32 +18,51 @@ */ package feature.blocked +import android.content.Context import com.uber.autodispose.android.lifecycle.scope import com.uber.autodispose.kotlin.autoDisposable +import common.Navigator +import common.base.QkViewModel import injection.appComponent import interactor.MarkUnblocked +import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.withLatestFrom -import common.base.QkViewModel import repository.MessageRepository +import util.Preferences +import util.tryOrNull import javax.inject.Inject class BlockedViewModel : QkViewModel(BlockedState()) { + @Inject lateinit var context: Context @Inject lateinit var markUnblocked: MarkUnblocked @Inject lateinit var messageRepo: MessageRepository + @Inject lateinit var navigator: Navigator + @Inject lateinit var prefs: Preferences init { appComponent.inject(this) - val conversations = messageRepo.getBlockedConversations() - .doOnNext { conversations -> newState { it.copy(empty = conversations.isEmpty()) } } + newState { it.copy(data = messageRepo.getBlockedConversations()) } - newState { it.copy(data = conversations) } + disposables += prefs.sia.asObservable() + .subscribe { enabled -> newState { it.copy(siaEnabled = enabled) } } } override fun bindView(view: BlockedView) { super.bindView(view) + view.siaClickedIntent + .map { + tryOrNull { context.packageManager.getApplicationInfo("org.mistergroup.shouldianswerpersonal", 0).enabled } + ?: tryOrNull { context.packageManager.getApplicationInfo("org.mistergroup.muzutozvednout", 0).enabled } + ?: false + } + .doOnNext { installed -> if (!installed) navigator.showSia() } + .withLatestFrom(prefs.sia.asObservable(), { installed, enabled -> installed && !enabled }) + .autoDisposable(view.scope()) + .subscribe { shouldEnable -> prefs.sia.set(shouldEnable) } + // Show confirm unblock conversation dialog view.unblockIntent .autoDisposable(view.scope()) diff --git a/presentation/src/main/res/layout/blocked_activity.xml b/presentation/src/main/res/layout/blocked_activity.xml index 6d5c24cf..47a1af18 100644 --- a/presentation/src/main/res/layout/blocked_activity.xml +++ b/presentation/src/main/res/layout/blocked_activity.xml @@ -43,18 +43,44 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/toolbar" /> - + app:layout_constraintTop_toBottomOf="@id/toolbar"> + + + + + + + + + + + + + xmlns:tools="http://schemas.android.com/tools" + tools:background="@color/white"> Notifications Vibration Sound - Blocked + Blocking + + Should I Answer? + Automatically filter messages from unsolicited numbers by using the \"Should I Answer\" app Delivery confirmations Confirm that messages were sent successfully QK Reply @@ -105,7 +108,7 @@ Sync messages Re-sync your messages with the native Android SMS database - Blocked + Blocking Your blocked conversations will appear here Unblock Would you like to unblock this conversation?