mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-03 11:17:32 +01:00
feat: account switch from bottom bar profile item (#1053)
This commit is contained in:
parent
6906a3ccc5
commit
4139e2d397
@ -82,6 +82,7 @@ kotlin {
|
|||||||
implementation(projects.unit.drawer)
|
implementation(projects.unit.drawer)
|
||||||
implementation(projects.unit.editcommunity)
|
implementation(projects.unit.editcommunity)
|
||||||
implementation(projects.unit.instanceinfo)
|
implementation(projects.unit.instanceinfo)
|
||||||
|
implementation(projects.unit.manageaccounts)
|
||||||
implementation(projects.unit.manageban)
|
implementation(projects.unit.manageban)
|
||||||
implementation(projects.unit.medialist)
|
implementation(projects.unit.medialist)
|
||||||
implementation(projects.unit.managesubscriptions)
|
implementation(projects.unit.managesubscriptions)
|
||||||
@ -124,9 +125,15 @@ kotlin {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.github.diegoberaldin.raccoonforlemmy"
|
namespace = "com.github.diegoberaldin.raccoonforlemmy"
|
||||||
compileSdk = libs.versions.android.targetSdk.get().toInt()
|
compileSdk =
|
||||||
|
libs.versions.android.targetSdk
|
||||||
|
.get()
|
||||||
|
.toInt()
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
minSdk =
|
||||||
|
libs.versions.android.minSdk
|
||||||
|
.get()
|
||||||
|
.toInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -41,12 +41,14 @@ import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getDrawerCoor
|
|||||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
|
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.ui.HomeTab
|
import com.github.diegoberaldin.raccoonforlemmy.feature.home.ui.HomeTab
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.ui.InboxTab
|
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.ui.InboxTab
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.ui.ProfileTab
|
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.ui.ProfileTab
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.feature.search.ui.ExploreTab
|
import com.github.diegoberaldin.raccoonforlemmy.feature.search.ui.ExploreTab
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.ui.SettingsTab
|
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.ui.SettingsTab
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.ui.navigation.TabNavigationItem
|
import com.github.diegoberaldin.raccoonforlemmy.ui.navigation.TabNavigationItem
|
||||||
|
import com.github.diegoberaldin.raccoonforlemmy.unit.manageaccounts.ManageAccountsScreen
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@ -246,6 +248,15 @@ internal object MainScreen : Screen {
|
|||||||
tab = ProfileTab,
|
tab = ProfileTab,
|
||||||
withText = titleVisible,
|
withText = titleVisible,
|
||||||
customIconUrl = uiState.customProfileUrl,
|
customIconUrl = uiState.customProfileUrl,
|
||||||
|
onLongPress =
|
||||||
|
if (uiState.isLogged) {
|
||||||
|
rememberCallback {
|
||||||
|
val screen = ManageAccountsScreen()
|
||||||
|
navigationCoordinator.showBottomSheet(screen)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
)
|
)
|
||||||
TabNavigationItem(
|
TabNavigationItem(
|
||||||
tab = InboxTab,
|
tab = InboxTab,
|
||||||
|
@ -15,6 +15,7 @@ interface MainScreenMviModel :
|
|||||||
data class UiState(
|
data class UiState(
|
||||||
val bottomBarOffsetHeightPx: Float = 0f,
|
val bottomBarOffsetHeightPx: Float = 0f,
|
||||||
val customProfileUrl: String? = null,
|
val customProfileUrl: String? = null,
|
||||||
|
val isLogged: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed interface Effect {
|
sealed interface Effect {
|
||||||
|
@ -50,7 +50,8 @@ class MainViewModel(
|
|||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
|
|
||||||
identityRepository.isLogged
|
identityRepository.isLogged
|
||||||
.onEach {
|
.onEach { isLogged ->
|
||||||
|
updateState { it.copy(isLogged = isLogged ?: false) }
|
||||||
updateCustomProfileIcon()
|
updateCustomProfileIcon()
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package com.github.diegoberaldin.raccoonforlemmy.ui.navigation
|
package com.github.diegoberaldin.raccoonforlemmy.ui.navigation
|
||||||
|
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.interaction.PressInteraction
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
@ -19,6 +22,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
|
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
|
||||||
import cafe.adriel.voyager.navigator.tab.Tab
|
import cafe.adriel.voyager.navigator.tab.Tab
|
||||||
@ -38,6 +42,7 @@ internal fun RowScope.TabNavigationItem(
|
|||||||
tab: Tab,
|
tab: Tab,
|
||||||
withText: Boolean = true,
|
withText: Boolean = true,
|
||||||
customIconUrl: String? = null,
|
customIconUrl: String? = null,
|
||||||
|
onLongPress: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val tabNavigator = LocalTabNavigator.current
|
val tabNavigator = LocalTabNavigator.current
|
||||||
val navigationCoordinator = remember { getNavigationCoordinator() }
|
val navigationCoordinator = remember { getNavigationCoordinator() }
|
||||||
@ -49,30 +54,52 @@ internal fun RowScope.TabNavigationItem(
|
|||||||
MaterialTheme.colorScheme.outline
|
MaterialTheme.colorScheme.outline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
|
||||||
|
fun handleClick() {
|
||||||
|
tabNavigator.current = tab
|
||||||
|
val section =
|
||||||
|
when (tab) {
|
||||||
|
ExploreTab -> TabNavigationSection.Explore
|
||||||
|
ProfileTab -> TabNavigationSection.Profile
|
||||||
|
InboxTab -> TabNavigationSection.Inbox
|
||||||
|
SettingsTab -> TabNavigationSection.Settings
|
||||||
|
else -> TabNavigationSection.Home
|
||||||
|
}
|
||||||
|
navigationCoordinator.setCurrentSection(section)
|
||||||
|
}
|
||||||
|
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
onClick = {
|
onClick = ::handleClick,
|
||||||
tabNavigator.current = tab
|
|
||||||
val section =
|
|
||||||
when (tab) {
|
|
||||||
ExploreTab -> TabNavigationSection.Explore
|
|
||||||
ProfileTab -> TabNavigationSection.Profile
|
|
||||||
InboxTab -> TabNavigationSection.Inbox
|
|
||||||
SettingsTab -> TabNavigationSection.Settings
|
|
||||||
else -> TabNavigationSection.Home
|
|
||||||
}
|
|
||||||
navigationCoordinator.setCurrentSection(section)
|
|
||||||
},
|
|
||||||
selected = tabNavigator.current == tab,
|
selected = tabNavigator.current == tab,
|
||||||
|
interactionSource = interactionSource,
|
||||||
icon = {
|
icon = {
|
||||||
val content = @Composable {
|
val content = @Composable {
|
||||||
if (customIconUrl != null) {
|
if (customIconUrl != null) {
|
||||||
val iconSize = IconSize.m
|
val iconSize = IconSize.m
|
||||||
|
|
||||||
CustomImage(
|
CustomImage(
|
||||||
url = customIconUrl,
|
url = customIconUrl,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.size(iconSize)
|
.size(iconSize)
|
||||||
.clip(RoundedCornerShape(iconSize / 2)),
|
.clip(RoundedCornerShape(iconSize / 2))
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectTapGestures(
|
||||||
|
onPress = { offset ->
|
||||||
|
val press = PressInteraction.Press(offset)
|
||||||
|
interactionSource.emit(press)
|
||||||
|
tryAwaitRelease()
|
||||||
|
interactionSource.emit(PressInteraction.Release(press))
|
||||||
|
},
|
||||||
|
onTap = {
|
||||||
|
handleClick()
|
||||||
|
},
|
||||||
|
onLongPress = {
|
||||||
|
onLongPress?.invoke()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Icon(
|
Icon(
|
||||||
|
@ -28,6 +28,7 @@ import androidx.compose.ui.graphics.FilterQuality
|
|||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.layout.positionInParent
|
import androidx.compose.ui.layout.positionInParent
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
|
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
|
||||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||||
@ -57,13 +58,12 @@ internal fun AccountItem(
|
|||||||
Row(
|
Row(
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
.fillMaxWidth()
|
|
||||||
.onClick(
|
.onClick(
|
||||||
onClick = {
|
onClick = {
|
||||||
onClick?.invoke()
|
onClick?.invoke()
|
||||||
},
|
},
|
||||||
).padding(
|
).padding(
|
||||||
horizontal = Spacing.m,
|
horizontal = Spacing.s,
|
||||||
vertical = Spacing.s,
|
vertical = Spacing.s,
|
||||||
),
|
),
|
||||||
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
@ -74,7 +74,6 @@ internal fun AccountItem(
|
|||||||
CustomImage(
|
CustomImage(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(Spacing.xxxs)
|
|
||||||
.size(IconSize.l)
|
.size(IconSize.l)
|
||||||
.clip(RoundedCornerShape(IconSize.l / 2)),
|
.clip(RoundedCornerShape(IconSize.l / 2)),
|
||||||
url = avatar,
|
url = avatar,
|
||||||
@ -85,7 +84,10 @@ internal fun AccountItem(
|
|||||||
} else {
|
} else {
|
||||||
Box(modifier = Modifier.size(IconSize.l))
|
Box(modifier = Modifier.size(IconSize.l))
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(0.8f),
|
||||||
|
maxLines = 1,
|
||||||
text =
|
text =
|
||||||
buildString {
|
buildString {
|
||||||
append(account.username)
|
append(account.username)
|
||||||
@ -93,6 +95,8 @@ internal fun AccountItem(
|
|||||||
append(account.instance)
|
append(account.instance)
|
||||||
},
|
},
|
||||||
color = fullColor,
|
color = fullColor,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
@ -108,12 +112,12 @@ internal fun AccountItem(
|
|||||||
Box {
|
Box {
|
||||||
Icon(
|
Icon(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.size(IconSize.m)
|
Modifier
|
||||||
|
.size(IconSize.m)
|
||||||
.padding(Spacing.xs)
|
.padding(Spacing.xs)
|
||||||
.onGloballyPositioned {
|
.onGloballyPositioned {
|
||||||
optionsOffset = it.positionInParent()
|
optionsOffset = it.positionInParent()
|
||||||
}
|
}.onClick(
|
||||||
.onClick(
|
|
||||||
onClick = {
|
onClick = {
|
||||||
optionsMenuOpen = true
|
optionsMenuOpen = true
|
||||||
},
|
},
|
||||||
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@ -48,13 +49,14 @@ class ManageAccountsScreen : Screen {
|
|||||||
var indexToDelete by remember { mutableStateOf<Int?>(null) }
|
var indexToDelete by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
LaunchedEffect(model) {
|
LaunchedEffect(model) {
|
||||||
model.effects.onEach { effect ->
|
model.effects
|
||||||
when (effect) {
|
.onEach { effect ->
|
||||||
ManageAccountsMviModel.Effect.Close -> {
|
when (effect) {
|
||||||
navigationCoordinator.hideBottomSheet()
|
ManageAccountsMviModel.Effect.Close -> {
|
||||||
|
navigationCoordinator.hideBottomSheet()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}.launchIn(this)
|
||||||
}.launchIn(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
@ -63,8 +65,6 @@ class ManageAccountsScreen : Screen {
|
|||||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||||
.padding(
|
.padding(
|
||||||
top = Spacing.s,
|
top = Spacing.s,
|
||||||
start = Spacing.s,
|
|
||||||
end = Spacing.s,
|
|
||||||
bottom = Spacing.m,
|
bottom = Spacing.m,
|
||||||
),
|
),
|
||||||
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||||
@ -78,6 +78,7 @@ class ManageAccountsScreen : Screen {
|
|||||||
) {
|
) {
|
||||||
itemsIndexed(uiState.accounts) { idx, account ->
|
itemsIndexed(uiState.accounts) { idx, account ->
|
||||||
AccountItem(
|
AccountItem(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
account = account,
|
account = account,
|
||||||
autoLoadImages = uiState.autoLoadImages,
|
autoLoadImages = uiState.autoLoadImages,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user