Migrate Preferences to new architecture
This commit is contained in:
parent
9e211b5e04
commit
ae273bd4ea
26 changed files with 399 additions and 174 deletions
|
|
@ -0,0 +1,41 @@
|
|||
package io.element.android.x.features.preferences
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.composable.Children
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.node.ParentNode
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import io.element.android.x.architecture.createNode
|
||||
import io.element.android.x.features.preferences.root.PreferencesRootNode
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
class PreferencesFlowNode(
|
||||
buildContext: BuildContext,
|
||||
private val backstack: BackStack<NavTarget> = BackStack(
|
||||
initialElement = NavTarget.Root,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
) : ParentNode<PreferencesFlowNode.NavTarget>(
|
||||
navModel = backstack,
|
||||
buildContext = buildContext
|
||||
) {
|
||||
|
||||
sealed interface NavTarget : Parcelable {
|
||||
@Parcelize
|
||||
object Root : NavTarget
|
||||
}
|
||||
|
||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.Root -> createNode<PreferencesRootNode>(buildContext)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
Children(navModel = backstack)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.features.preferences
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.x.designsystem.components.preferences.PreferenceScreen
|
||||
import io.element.android.x.element.resources.R as ElementR
|
||||
import io.element.android.x.features.logout.LogoutPreference
|
||||
import io.element.android.x.features.preferences.user.UserPreferences
|
||||
import io.element.android.x.features.rageshake.preferences.RageshakePreferences
|
||||
|
||||
@Composable
|
||||
fun PreferencesScreen(
|
||||
onBackPressed: () -> Unit = {},
|
||||
onOpenRageShake: () -> Unit = {},
|
||||
onSuccessLogout: () -> Unit = {},
|
||||
) {
|
||||
// TODO Hierarchy!
|
||||
// Include pref from other modules
|
||||
PreferencesContent(
|
||||
onBackPressed = onBackPressed,
|
||||
onOpenRageShake = onOpenRageShake,
|
||||
onSuccessLogout = onSuccessLogout,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PreferencesContent(
|
||||
modifier: Modifier = Modifier,
|
||||
onBackPressed: () -> Unit = {},
|
||||
onOpenRageShake: () -> Unit = {},
|
||||
onSuccessLogout: () -> Unit = {},
|
||||
) {
|
||||
PreferenceScreen(
|
||||
modifier = modifier,
|
||||
onBackPressed = onBackPressed,
|
||||
title = stringResource(id = ElementR.string.settings)
|
||||
) {
|
||||
UserPreferences()
|
||||
RageshakePreferences(onOpenRageShake = onOpenRageShake)
|
||||
LogoutPreference(onSuccessLogout = onSuccessLogout)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferencesContentPreview() {
|
||||
PreferencesContent()
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package io.element.android.x.features.preferences.root
|
||||
|
||||
sealed interface PreferencesRootEvents {
|
||||
object Logout : PreferencesRootEvents
|
||||
data class SetRageshakeSensitivity(val sensitivity: Float) : PreferencesRootEvents
|
||||
data class SetRageshakeEnabled(val enabled: Boolean) : PreferencesRootEvents
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package io.element.android.x.features.preferences.root
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.x.anvilannotations.ContributesNode
|
||||
import io.element.android.x.architecture.presenterConnector
|
||||
import io.element.android.x.di.SessionScope
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class PreferencesRootNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: PreferencesRootPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
|
||||
private val presenterConnector = presenterConnector(presenter)
|
||||
|
||||
private fun onLogoutClicked() {
|
||||
presenterConnector.emitEvent(PreferencesRootEvents.Logout)
|
||||
}
|
||||
|
||||
private fun onRageshakeEnabledChanged(isEnabled: Boolean) {
|
||||
presenterConnector.emitEvent(PreferencesRootEvents.SetRageshakeEnabled(isEnabled))
|
||||
}
|
||||
|
||||
private fun onRageshakeSensitivityChanged(sensitivity: Float) {
|
||||
presenterConnector.emitEvent(PreferencesRootEvents.SetRageshakeSensitivity(sensitivity))
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state by presenterConnector.stateFlow.collectAsState()
|
||||
PreferencesRootView(
|
||||
state = state,
|
||||
onLogoutClicked = this::onLogoutClicked,
|
||||
onBackPressed = this::navigateUp,
|
||||
onRageshakeEnabledChanged = this::onRageshakeEnabledChanged,
|
||||
onRageshakeSensitivityChanged = this::onRageshakeSensitivityChanged
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package io.element.android.x.features.preferences.root
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import io.element.android.x.architecture.Async
|
||||
import io.element.android.x.architecture.Presenter
|
||||
import io.element.android.x.architecture.SharedFlowHolder
|
||||
import io.element.android.x.features.logout.LogoutPreferenceEvents
|
||||
import io.element.android.x.features.logout.LogoutPreferencePresenter
|
||||
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesEvents
|
||||
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesPresenter
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
|
||||
class PreferencesRootPresenter @Inject constructor(
|
||||
private val logoutPresenter: LogoutPreferencePresenter,
|
||||
private val rageshakePresenter: RageshakePreferencesPresenter,
|
||||
) : Presenter<PreferencesRootState, PreferencesRootEvents> {
|
||||
|
||||
private val logoutEventsFlow = SharedFlowHolder<LogoutPreferenceEvents>()
|
||||
private val rageshakeEventsFlow = SharedFlowHolder<RageshakePreferencesEvents>()
|
||||
|
||||
@Composable
|
||||
override fun present(events: Flow<PreferencesRootEvents>): PreferencesRootState {
|
||||
val logoutState = logoutPresenter.present(events = logoutEventsFlow.asSharedFlow())
|
||||
val rageshakeState = rageshakePresenter.present(events = rageshakeEventsFlow.asSharedFlow())
|
||||
LaunchedEffect(Unit) {
|
||||
events.collect { event ->
|
||||
when (event) {
|
||||
PreferencesRootEvents.Logout -> logoutEventsFlow.emit(LogoutPreferenceEvents.Logout)
|
||||
is PreferencesRootEvents.SetRageshakeEnabled -> rageshakeEventsFlow.emit(RageshakePreferencesEvents.SetIsEnabled(event.enabled))
|
||||
is PreferencesRootEvents.SetRageshakeSensitivity -> rageshakeEventsFlow.emit(RageshakePreferencesEvents.SetSensitivity(event.sensitivity))
|
||||
}
|
||||
}
|
||||
}
|
||||
return PreferencesRootState(
|
||||
logoutState = logoutState,
|
||||
rageshakeState = rageshakeState,
|
||||
myUser = Async.Uninitialized
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package io.element.android.x.features.preferences.root
|
||||
|
||||
import io.element.android.x.architecture.Async
|
||||
import io.element.android.x.features.logout.LogoutPreferenceState
|
||||
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesState
|
||||
import io.element.android.x.matrix.ui.model.MatrixUser
|
||||
|
||||
data class PreferencesRootState(
|
||||
val logoutState: LogoutPreferenceState,
|
||||
val rageshakeState: RageshakePreferencesState,
|
||||
val myUser: Async<MatrixUser>,
|
||||
)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package io.element.android.x.features.preferences.root
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.x.architecture.Async
|
||||
import io.element.android.x.designsystem.components.preferences.PreferenceView
|
||||
import io.element.android.x.element.resources.R
|
||||
import io.element.android.x.features.logout.LogoutPreferenceState
|
||||
import io.element.android.x.features.logout.LogoutPreferenceView
|
||||
import io.element.android.x.features.preferences.user.UserPreferences
|
||||
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesState
|
||||
import io.element.android.x.features.rageshake.preferences.RageshakePreferencesView
|
||||
|
||||
@Composable
|
||||
fun PreferencesRootView(
|
||||
state: PreferencesRootState,
|
||||
modifier: Modifier = Modifier,
|
||||
onBackPressed: () -> Unit = {},
|
||||
onLogoutClicked: () -> Unit = {},
|
||||
onOpenRageShake: () -> Unit = {},
|
||||
onRageshakeEnabledChanged: (Boolean) -> Unit = {},
|
||||
onRageshakeSensitivityChanged: (Float) -> Unit = {},
|
||||
) {
|
||||
// TODO Hierarchy!
|
||||
// Include pref from other modules
|
||||
PreferenceView(
|
||||
modifier = modifier,
|
||||
onBackPressed = onBackPressed,
|
||||
title = stringResource(id = R.string.settings)
|
||||
) {
|
||||
UserPreferences(state.myUser)
|
||||
RageshakePreferencesView(
|
||||
state = state.rageshakeState,
|
||||
onOpenRageshake = onOpenRageShake,
|
||||
onSensitivityChanged = onRageshakeSensitivityChanged,
|
||||
onIsEnabledChanged = onRageshakeEnabledChanged,
|
||||
)
|
||||
LogoutPreferenceView(
|
||||
state = state.logoutState,
|
||||
onLogoutClicked = onLogoutClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreferencesContentPreview() {
|
||||
val state = PreferencesRootState(
|
||||
logoutState = LogoutPreferenceState(),
|
||||
rageshakeState = RageshakePreferencesState(),
|
||||
myUser = Async.Uninitialized
|
||||
)
|
||||
PreferencesRootView(state)
|
||||
}
|
||||
|
|
@ -19,26 +19,22 @@ package io.element.android.x.features.preferences.user
|
|||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.airbnb.mvrx.compose.collectAsState
|
||||
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||
import io.element.android.x.architecture.Async
|
||||
import io.element.android.x.matrix.ui.components.MatrixUserHeader
|
||||
import io.element.android.x.matrix.ui.viewmodels.user.UserViewModel
|
||||
import io.element.android.x.matrix.ui.viewmodels.user.UserViewState
|
||||
import io.element.android.x.matrix.ui.model.MatrixUser
|
||||
|
||||
@Composable
|
||||
fun UserPreferences(
|
||||
user: Async<MatrixUser>,
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: UserViewModel = mavericksViewModel(),
|
||||
) {
|
||||
val user by viewModel.collectAsState(UserViewState::user)
|
||||
when (user()) {
|
||||
when (val userData = user.dataOrNull()) {
|
||||
null -> Spacer(modifier = modifier.height(1.dp))
|
||||
else -> MatrixUserHeader(
|
||||
modifier = modifier,
|
||||
matrixUser = user.invoke()!!
|
||||
matrixUser = userData
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue