Handle Duplicate Registered Host on Android

This commit is contained in:
Florian Märkl 2019-10-16 15:47:15 +02:00
commit 98f9f3f6e9
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
6 changed files with 74 additions and 24 deletions

View file

@ -20,6 +20,7 @@ package com.metallic.chiaki.common
import androidx.room.* import androidx.room.*
import androidx.room.ColumnInfo.BLOB import androidx.room.ColumnInfo.BLOB
import com.metallic.chiaki.lib.RegistHost import com.metallic.chiaki.lib.RegistHost
import io.reactivex.Completable
import io.reactivex.Flowable import io.reactivex.Flowable
import io.reactivex.Maybe import io.reactivex.Maybe
import io.reactivex.Single import io.reactivex.Single
@ -61,6 +62,9 @@ interface RegisteredHostDao
@Query("SELECT * FROM registered_host WHERE ps4_mac == :mac LIMIT 1") @Query("SELECT * FROM registered_host WHERE ps4_mac == :mac LIMIT 1")
fun getByMac(mac: MacAddress): Maybe<RegisteredHost> fun getByMac(mac: MacAddress): Maybe<RegisteredHost>
@Query("DELETE FROM registered_host WHERE ps4_mac == :mac")
fun deleteByMac(mac: MacAddress): Completable
@Insert @Insert
fun insert(host: RegisteredHost): Single<Long> fun insert(host: RegisteredHost): Single<Long>
} }

View file

@ -18,6 +18,8 @@
package com.metallic.chiaki.regist package com.metallic.chiaki.regist
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.method.ScrollingMovementMethod import android.text.method.ScrollingMovementMethod
@ -26,6 +28,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import com.metallic.chiaki.R import com.metallic.chiaki.R
import com.metallic.chiaki.common.MacAddress
import com.metallic.chiaki.common.ext.viewModelFactory import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase import com.metallic.chiaki.common.getDatabase
import com.metallic.chiaki.lib.RegistInfo import com.metallic.chiaki.lib.RegistInfo
@ -70,11 +73,13 @@ class RegistExecuteActivity: AppCompatActivity()
infoTextView.setText(R.string.regist_info_failed) infoTextView.setText(R.string.regist_info_failed)
setResult(RESULT_FAILED) setResult(RESULT_FAILED)
} }
RegistExecuteViewModel.State.SUCCESSFUL -> RegistExecuteViewModel.State.SUCCESSFUL, RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE ->
{ {
infoTextView.visibility = View.VISIBLE infoTextView.visibility = View.VISIBLE
infoTextView.setText(R.string.regist_info_success) infoTextView.setText(R.string.regist_info_success)
setResult(RESULT_OK) setResult(RESULT_OK)
if(it == RegistExecuteViewModel.State.SUCCESSFUL_DUPLICATE)
showDuplicateDialog()
} }
RegistExecuteViewModel.State.STOPPED -> RegistExecuteViewModel.State.STOPPED ->
{ {
@ -108,4 +113,24 @@ class RegistExecuteActivity: AppCompatActivity()
super.onStop() super.onStop()
viewModel.stop() viewModel.stop()
} }
private var dialog: AlertDialog? = null
private fun showDuplicateDialog()
{
if(dialog != null)
return
val macStr = viewModel.host?.ps4Mac?.let { MacAddress(it).toString() } ?: ""
dialog = AlertDialog.Builder(this)
.setMessage(getString(R.string.alert_regist_duplicate, macStr))
.setNegativeButton(R.string.action_regist_discard) { _, _ -> }
.setPositiveButton(R.string.action_regist_overwrite) { _, _ ->
viewModel.saveHost()
}
.create()
.also { it.show() }
}
} }

View file

@ -18,7 +18,6 @@
package com.metallic.chiaki.regist package com.metallic.chiaki.regist
import android.util.Log import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@ -29,6 +28,7 @@ import com.metallic.chiaki.common.ext.toLiveData
import com.metallic.chiaki.lib.* import com.metallic.chiaki.lib.*
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Action
import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.addTo
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
@ -40,7 +40,8 @@ class RegistExecuteViewModel(val database: AppDatabase): ViewModel()
RUNNING, RUNNING,
STOPPED, STOPPED,
FAILED, FAILED,
SUCCESSFUL SUCCESSFUL,
SUCCESSFUL_DUPLICATE,
} }
private val _state = MutableLiveData<State>(State.IDLE) private val _state = MutableLiveData<State>(State.IDLE)
@ -53,6 +54,9 @@ class RegistExecuteViewModel(val database: AppDatabase): ViewModel()
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
var host: RegistHost? = null
private set
fun start(info: RegistInfo) fun start(info: RegistInfo)
{ {
if(regist != null) if(regist != null)
@ -86,28 +90,33 @@ class RegistExecuteViewModel(val database: AppDatabase): ViewModel()
private fun registSuccess(host: RegistHost) private fun registSuccess(host: RegistHost)
{ {
_state.postValue(State.SUCCESSFUL) // TODO: more states this.host = host
database.registeredHostDao().getByMac(MacAddress(host.ps4Mac))
val dao = database.registeredHostDao()
val mac = MacAddress(host.ps4Mac)
//val mac = MacAddress(byteArrayOf(0xc0.toByte(), 0xff.toByte(), 0xff.toByte(), 0xee.toByte(), 0xee.toByte(), 0x42))
dao.getByMac(mac)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doOnSuccess { .doOnSuccess {
// TODO: show dialog _state.value = State.SUCCESSFUL_DUPLICATE
Log.i("RegistExecuteViewModel", "already exists")
} }
.doOnComplete { .doOnComplete {
dao.insert(RegisteredHost(host)) saveHost()
.subscribeOn(Schedulers.io()) }
.subscribe() .subscribe()
.addTo(disposable) .addTo(disposable)
} }
.subscribe()
fun saveHost()
{
val host = host ?: return
val dao = database.registeredHostDao()
val registeredHost = RegisteredHost(host)
dao.deleteByMac(registeredHost.ps4Mac)
.andThen(dao.insert(registeredHost))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { _ ->
Log.i("RegistExecute", "Registered Host saved in db")
_state.value = State.SUCCESSFUL
}
.addTo(disposable) .addTo(disposable)
} }

View file

@ -126,8 +126,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textVisiblePassword" android:inputType="textNoSuggestions|textVisiblePassword"
android:maxLines="1" android:maxLines="1"/>
android:text="test"/>
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -175,8 +174,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="number" android:inputType="number"
android:maxLength="8" android:maxLength="8"/>
android:text="01234567"/>
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton

View file

@ -35,4 +35,7 @@
<string name="action_share_log">Share Log</string> <string name="action_share_log">Share Log</string>
<string name="regist_info_success">Regist successful.</string> <string name="regist_info_success">Regist successful.</string>
<string name="regist_info_failed">Regist failed.</string> <string name="regist_info_failed">Regist failed.</string>
<string name="alert_regist_duplicate">The console with MAC %s has already been registered. Should the previous record be overwritten?</string>
<string name="action_regist_overwrite">Overwrite</string>
<string name="action_regist_discard">Cancel</string>
</resources> </resources>

View file

@ -35,7 +35,7 @@
<item name="android:navigationBarColor">?attr/colorPrimarySurface</item> <item name="android:navigationBarColor">?attr/colorPrimarySurface</item>
<item name="colorControlNormal">@color/accent</item> <item name="colorControlNormal">@color/accent</item>
<item name="colorButtonNormal">@color/accent</item> <item name="colorButtonNormal">@color/accent</item>
<item name="android:textAppearanceButton">@style/TextAppearanceButton</item> <item name="android:textAppearanceButton">@style/MageTheme.TextAppearanceButton</item>
<item name="android:textColor">?attr/colorOnPrimary</item> <item name="android:textColor">?attr/colorOnPrimary</item>
<item name="textAppearanceHeadline1">@style/MageTheme.TextAppearanceHeadline1</item> <item name="textAppearanceHeadline1">@style/MageTheme.TextAppearanceHeadline1</item>
@ -47,6 +47,8 @@
<item name="android:windowActivityTransitions">true</item> <item name="android:windowActivityTransitions">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:alertDialogTheme">@style/MageTheme.AlertDialog</item>
</style> </style>
<style name="MageTheme.Translucent" parent="MageTheme"> <style name="MageTheme.Translucent" parent="MageTheme">
@ -57,6 +59,15 @@
<item name="fontFamily">sans-serif-condensed-light</item> <item name="fontFamily">sans-serif-condensed-light</item>
</style> </style>
<style name="MageTheme.AlertDialog" parent="Theme.MaterialComponents.Dialog.Alert">
<item name="android:textColorPrimary">@android:color/primary_text_light</item>
<item name="materialButtonStyle">@style/MageTheme.AlertDialog.Button</item>
</style>
<style name="MageTheme.AlertDialog.Button" parent="Widget.MaterialComponents.Button.TextButton.Dialog">
<item name="android:textColor">@color/accent</item>
</style>
<style name="MageTheme.TextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.FilledBox"> <style name="MageTheme.TextInputStyle" parent="Widget.MaterialComponents.TextInputLayout.FilledBox">
<item name="hintTextColor">?attr/colorAccent</item> <item name="hintTextColor">?attr/colorAccent</item>
<item name="boxCornerRadiusTopStart">16dp</item> <item name="boxCornerRadiusTopStart">16dp</item>
@ -72,7 +83,7 @@
<item name="iconTint">?attr/colorOnSecondary</item> <item name="iconTint">?attr/colorOnSecondary</item>
</style> </style>
<style name="TextAppearanceButton" parent="TextAppearance.MaterialComponents.Button"> <style name="MageTheme.TextAppearanceButton" parent="TextAppearance.MaterialComponents.Button">
<item name="android:textColor">?attr/colorOnSecondary</item> <item name="android:textColor">?attr/colorOnSecondary</item>
</style> </style>