Skip to content

Commit

Permalink
#378 customise fingerprint gesture options
Browse files Browse the repository at this point in the history
  • Loading branch information
sds100 committed Nov 19, 2020
1 parent 4ad75c0 commit 4cac4e0
Show file tree
Hide file tree
Showing 13 changed files with 515 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ data class FingerprintGestureMap(

FingerprintGestureMap(action, extras, flags, isEnabled)
}

const val FLAG_VIBRATE = 1

const val EXTRA_VIBRATION_DURATION = "extra_vibration_duration"
}

fun clone(action: Action? = this.action,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.github.sds100.keymapper.data.model.behavior

import io.github.sds100.keymapper.data.model.FingerprintGestureMap
import io.github.sds100.keymapper.data.model.behavior.BehaviorOption.Companion.applyBehaviorOption
import io.github.sds100.keymapper.data.model.getData
import io.github.sds100.keymapper.util.result.valueOrNull
import splitties.bitflags.hasFlag
import java.io.Serializable

/**
* Created by sds100 on 18/11/20.
*/

class FingerprintGestureMapOptions(val gestureId: String, fingerprintGestureMap: FingerprintGestureMap) : Serializable {
companion object {
const val ID_VIBRATE = "vibrate"
const val ID_VIBRATION_DURATION = "vibration_duration"
}

val vibrate = BehaviorOption(
id = ID_VIBRATE,
value = fingerprintGestureMap.flags.hasFlag(FingerprintGestureMap.FLAG_VIBRATE),
isAllowed = true
)

val vibrateDuration: BehaviorOption<Int>

init {
val vibrateDurationValue =
fingerprintGestureMap.extras.getData(FingerprintGestureMap.EXTRA_VIBRATION_DURATION).valueOrNull()?.toInt()

vibrateDuration = BehaviorOption(
id = ID_VIBRATION_DURATION,
value = vibrateDurationValue ?: BehaviorOption.DEFAULT,
isAllowed = vibrate.value
)

}

fun setValue(id: String, value: Boolean): FingerprintGestureMapOptions {
when (id) {
ID_VIBRATE -> {
vibrate.value = value
vibrateDuration.isAllowed = value
}
}

return this
}

fun setValue(id: String, value: Int): FingerprintGestureMapOptions {
when (id) {
ID_VIBRATION_DURATION -> vibrateDuration.value = value
}

return this
}

fun applyToFingerprintGestureMap(fingerprintGestureMap: FingerprintGestureMap): FingerprintGestureMap {
val newFlags = fingerprintGestureMap.flags
.applyBehaviorOption(vibrate, FingerprintGestureMap.FLAG_VIBRATE)

val newExtras = fingerprintGestureMap.extras
.applyBehaviorOption(vibrateDuration, FingerprintGestureMap.EXTRA_VIBRATION_DURATION)

return fingerprintGestureMap.clone(flags = newFlags, extras = newExtras)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package io.github.sds100.keymapper.data.viewmodel

import android.os.Bundle
import androidx.lifecycle.*
import io.github.sds100.keymapper.R
import io.github.sds100.keymapper.data.model.CheckBoxListItemModel
import io.github.sds100.keymapper.data.model.SliderListItemModel
import io.github.sds100.keymapper.data.model.SliderModel
import io.github.sds100.keymapper.data.model.behavior.BehaviorOption.Companion.nullIfDefault
import io.github.sds100.keymapper.data.model.behavior.FingerprintGestureMapOptions
import io.github.sds100.keymapper.util.Data
import io.github.sds100.keymapper.util.Loading
import io.github.sds100.keymapper.util.State
import io.github.sds100.keymapper.util.ifIsData
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch

/**
* Created by sds100 on 18/11/20.
*/

class FingerprintGestureMapOptionsViewModel : ViewModel() {
companion object {
private const val STATE_KEY = "state_fingerprint_gesture_map_behavior"
}

private val _options: MutableLiveData<State<FingerprintGestureMapOptions>> = MutableLiveData(Loading())
val options: LiveData<State<FingerprintGestureMapOptions>> = _options

private val _onSave: MutableSharedFlow<FingerprintGestureMapOptions> = MutableSharedFlow()
val onSave = _onSave.asSharedFlow()

fun setOptions(behavior: FingerprintGestureMapOptions) {
_options.value = Data(behavior)
}

val checkBoxModels = options.map {
if (it !is Data) return@map listOf()

return@map sequence {
if (it.data.vibrate.isAllowed) {
yield(CheckBoxListItemModel(
id = it.data.vibrate.id,
label = R.string.flag_vibrate,
isChecked = it.data.vibrate.value
))
}
}.toList()
}

val sliderModels = options.map {
if (it !is Data) return@map listOf()

return@map sequence {
if (it.data.vibrateDuration.isAllowed) {
yield(SliderListItemModel(
id = it.data.vibrateDuration.id,
label = R.string.extra_label_vibration_duration,
sliderModel = SliderModel(
value = it.data.vibrateDuration.value.nullIfDefault,
isDefaultStepEnabled = true,
min = R.integer.vibrate_duration_min,
maxSlider = R.integer.vibrate_duration_max,
stepSize = R.integer.vibrate_duration_step_size
)
))
}

}.toList()
}

fun setValue(id: String, newValue: Int) {
options.value?.ifIsData {
_options.value = Data(it.setValue(id, newValue))
}
}

fun setValue(id: String, newValue: Boolean) {
options.value?.ifIsData {
_options.value = Data(it.setValue(id, newValue))
}
}

fun save() {
options.value?.ifIsData {
viewModelScope.launch {
_onSave.emit(it)
}
}
}

fun saveState(outState: Bundle) {
options.value?.ifIsData {
outState.putSerializable(STATE_KEY, it)
}
}

fun restoreState(state: Bundle) {
_options.value = Loading()

val behavior = state.getSerializable(STATE_KEY) as FingerprintGestureMapOptions
setOptions(behavior)
}

@Suppress("UNCHECKED_CAST")
class Factory : ViewModelProvider.NewInstanceFactory() {

override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return FingerprintGestureMapOptionsViewModel() as T
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package io.github.sds100.keymapper.data.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.*
import io.github.sds100.keymapper.data.model.Action
import io.github.sds100.keymapper.data.model.FingerprintGestureMap
import io.github.sds100.keymapper.data.model.FingerprintGestureMapListItemModel
import io.github.sds100.keymapper.data.model.behavior.FingerprintGestureMapOptions
import io.github.sds100.keymapper.data.repository.FingerprintGestureRepository
import io.github.sds100.keymapper.util.Data
import io.github.sds100.keymapper.util.FingerprintGestureUtils
Expand All @@ -23,11 +22,14 @@ class FingerprintGestureViewModel(private val mRepository: FingerprintGestureRep
)
}

private val _models: MutableStateFlow<State<List<FingerprintGestureMapListItemModel>>> = MutableStateFlow(Loading())
val models = _models.asStateFlow()
private val _models: MutableLiveData<State<List<FingerprintGestureMapListItemModel>>> = MutableLiveData(Loading())
val models: LiveData<State<List<FingerprintGestureMapListItemModel>>> = _models

private val _buildModels: MutableSharedFlow<Map<String, FingerprintGestureMap>> = MutableSharedFlow()
val buildModels: SharedFlow<Map<String, FingerprintGestureMap>> = _buildModels
val buildModels = _buildModels.asSharedFlow()

private val _editOptions: MutableSharedFlow<FingerprintGestureMapOptions> = MutableSharedFlow()
val editOptions = _editOptions.asSharedFlow()

init {
viewModelScope.launch {
Expand All @@ -38,7 +40,7 @@ class FingerprintGestureViewModel(private val mRepository: FingerprintGestureRep
}

fun setModels(models: List<FingerprintGestureMapListItemModel>) = viewModelScope.launch {
_models.emit(Data(models))
_models.value = Data(models)
}

fun setAction(id: String, action: Action) {
Expand All @@ -62,13 +64,28 @@ class FingerprintGestureViewModel(private val mRepository: FingerprintGestureRep
}

fun rebuildModels() = viewModelScope.launch {
_models.emit(Loading())
_models.value = Loading()

mFingerprintGestureMaps.firstOrNull()?.let {
_buildModels.emit(it)
}
}

fun editOptions(gestureId: String) = viewModelScope.launch {
mFingerprintGestureMaps.firstOrNull()?.get(gestureId)?.let {
val options = FingerprintGestureMapOptions(gestureId, it)
_editOptions.emit(options)
}
}

fun setOptions(options: FingerprintGestureMapOptions) = viewModelScope.launch {
mFingerprintGestureMaps.firstOrNull()?.get(options.gestureId)?.let {
val newMap = options.applyToFingerprintGestureMap(it)

mRepository.edit(options.gestureId) { newMap }
}
}

@Suppress("UNCHECKED_CAST")
class Factory(private val mRepository: FingerprintGestureRepository) : ViewModelProvider.NewInstanceFactory() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,43 +45,45 @@ class FingerprintGestureFragment : DefaultRecyclerViewFragment() {
override fun subscribeList(binding: FragmentRecyclerviewBinding) {
binding.caption = str(R.string.caption_fingerprint_gesture)

viewLifecycleScope.launchWhenStarted {
mViewModel.models.collect { models ->
binding.state = models
mViewModel.models.observe(viewLifecycleOwner, { models ->
binding.state = models

if (models !is Data) return@collect
if (models !is Data) return@observe

binding.epoxyRecyclerView.withModels {
models.data.forEach {
fingerprintGesture {
id(it.id)
model(it)
binding.epoxyRecyclerView.withModels {
models.data.forEach {
fingerprintGesture {
id(it.id)
model(it)

onChooseActionClick { _ ->
val direction = HomeFragmentDirections.actionHomeFragmentToChooseActionFragment(
FingerprintGestureUtils.CHOOSE_ACTION_REQUEST_KEYS[it.id]!!)
onChooseActionClick { _ ->
val direction = HomeFragmentDirections.actionHomeFragmentToChooseActionFragment(
FingerprintGestureUtils.CHOOSE_ACTION_REQUEST_KEYS[it.id]!!)

findNavController().navigate(direction)
}
findNavController().navigate(direction)
}

onRemoveActionClick { _ ->
mViewModel.removeAction(it.id)
}
onRemoveActionClick { _ ->
mViewModel.removeAction(it.id)
}

fixAction { _ ->
if (it.actionModel?.failure is RecoverableFailure) {
mRecoverFailureDelegate.recover(requireActivity(), it.actionModel.failure)
}
fixAction { _ ->
if (it.actionModel?.failure is RecoverableFailure) {
mRecoverFailureDelegate.recover(requireActivity(), it.actionModel.failure)
}
}

onEnabledSwitchChangeListener { _, isChecked ->
mViewModel.setEnabled(it.id, isChecked)
}
onEnabledSwitchChangeListener { _, isChecked ->
mViewModel.setEnabled(it.id, isChecked)
}

onOptionsClick { _ ->
mViewModel.editOptions(it.id)
}
}
}
}
}
})

viewLifecycleScope.launchWhenStarted {
mViewModel.buildModels.collect { gestureMaps ->
Expand All @@ -97,5 +99,15 @@ class FingerprintGestureFragment : DefaultRecyclerViewFragment() {
mViewModel.setModels(models)
}
}

viewLifecycleScope.launchWhenStarted {
mViewModel.editOptions.collect {
val requestKey = FingerprintGestureUtils.OPTIONS_REQUEST_KEYS[it.gestureId]!!

val direction =
HomeFragmentDirections.actionHomeFragmentToFingerprintGestureMapBehaviorFragment(it, requestKey)
findNavController().navigate(direction)
}
}
}
}
Loading

0 comments on commit 4cac4e0

Please sign in to comment.