这是indexloc提供的服务,不要输入任何密码
Skip to content

Three pane flourishes #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion libraryVersion.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
groupId=com.tunjid.treenav
treenav_version=0.0.7
strings_version=0.0.7
adaptive_version=0.0.7
compose_version=0.0.7
4 changes: 2 additions & 2 deletions sample/android/src/main/java/com/tunjid/tyler/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import com.tunjid.demo.common.ui.AppTheme
import com.tunjid.demo.common.ui.App
import com.tunjid.demo.common.ui.SampleApp

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AppTheme {
App()
SampleApp()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion sample/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ kotlin {
dependencies {
implementation(project(":library:treenav"))
implementation(project(":library:strings"))
implementation(project(":library:adaptive"))
implementation(project(":library:compose"))

implementation(compose.components.resources)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,9 @@
package com.tunjid.demo.common.ui


import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.splineBasedDecay
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -38,70 +29,30 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tunjid.composables.collapsingheader.CollapsingHeader
import com.tunjid.composables.collapsingheader.CollapsingHeaderState
import kotlin.math.max
import kotlin.math.roundToInt

@Composable
internal fun SampleCollapsingHeader(
title: String,
headerColor: Color,
onBackPressed: () -> Unit,
body: @Composable (collapsedHeight: Float) -> Unit,
) {
fun rememberAppBarCollapsingHeaderState(
expandedHeight: Dp
): CollapsingHeaderState {
val density = LocalDensity.current
val collapsedHeight = with(density) { 56.dp.toPx() } +
WindowInsets.statusBars.getTop(density).toFloat() +
WindowInsets.statusBars.getBottom(density).toFloat()
val headerState = remember {

return remember {
CollapsingHeaderState(
collapsedHeight = collapsedHeight,
initialExpandedHeight = with(density) { 400.dp.toPx() },
initialExpandedHeight = with(density) { expandedHeight.toPx() },
decayAnimationSpec = splineBasedDecay(density)
)
}
val animatedColor by animateColorAsState(
headerColor.copy(alpha = max(1f - headerState.progress, 0.6f))
)
CollapsingHeader(
state = headerState,
headerContent = {
Box {
Column(
modifier = Modifier.fillMaxWidth()
.offset {
IntOffset(
x = 0,
y = -headerState.translation.roundToInt()
)
}
.background(animatedColor)
) {
Spacer(Modifier.windowInsetsPadding(WindowInsets.statusBars))
Spacer(Modifier.height(200.dp))
}
SampleTopAppBar(
title = title,
onBackPressed = onBackPressed,
modifier = Modifier.onSizeChanged {
headerState.collapsedHeight = it.height.toFloat()
}
)
}
},
body = {
body(collapsedHeight)
}
)
}

@OptIn(ExperimentalMaterial3Api::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,14 @@ import kotlin.math.roundToInt

@OptIn(ExperimentalSharedTransitionApi::class, ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun App(
fun SampleApp(
appState: SampleAppState = remember { SampleAppState() },
) {
NavigationSuiteScaffold(
navigationSuiteItems = {
SampleDestination.NavTabs.entries.forEach {
item(
icon = {
Icon(
it.icon,
contentDescription = it.title
)
},
icon = { Icon(it.icon, contentDescription = it.title) },
label = { Text(it.title) },
selected = it == appState.currentNavigation.current,
onClick = { }
Expand Down Expand Up @@ -109,7 +104,6 @@ fun App(
.onSizeChanged {
windowWidthDp.value = (it.width / density.density).roundToInt()
}
then sharedTransitionModifier
) {
ListDetailPaneScaffold(
modifier = Modifier
Expand All @@ -123,21 +117,23 @@ fun App(
tertiary = if (nodeFor(ThreePane.Tertiary) == null) PaneAdaptedValue.Hidden else PaneAdaptedValue.Expanded,
),
listPane = {
Destination(ThreePane.Secondary)
if (nodeFor(ThreePane.Tertiary) == null) Destination(ThreePane.Secondary)
else Destination(ThreePane.Tertiary)
},
detailPane = {
Destination(ThreePane.Primary)
if (nodeFor(ThreePane.Tertiary) == null) Destination(ThreePane.Primary)
else Destination(ThreePane.Secondary)
},
extraPane = {
Destination(ThreePane.Tertiary)
if (nodeFor(ThreePane.Tertiary) == null) Destination(ThreePane.Tertiary)
else Destination(ThreePane.Primary)
}
)
}
}
}
}


@Stable
class SampleAppState(
private val navigationRepository: NavigationRepository = NavigationRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand Down Expand Up @@ -68,12 +69,17 @@ fun ChatScreen(
) {
SampleTopAppBar(
title = state.room?.name ?: "",
onBackPressed = { onAction(Action.Navigation.Pop) },
onBackPressed = remember(state.isInPrimaryPane) {
if (state.isInPrimaryPane) return@remember {
onAction(Action.Navigation.Pop)
} else null
},
)
Messages(
me = state.me,
roomName = state.room?.name,
messages = state.chats,
isInPrimaryPane = state.isInPrimaryPane,
navigateToProfile = onAction,
modifier = Modifier.weight(1f),
scrollState = scrollState,
Expand All @@ -87,6 +93,7 @@ fun ChatScreen(
fun Messages(
me: Profile?,
roomName: String?,
isInPrimaryPane: Boolean,
messages: List<MessageItem>,
navigateToProfile: (Action.Navigation.GoToProfile) -> Unit,
scrollState: LazyListState,
Expand All @@ -113,6 +120,7 @@ fun Messages(
roomName = roomName,
item = content,
isUserMe = content.sender.name == me?.name,
isInPrimaryPane = isInPrimaryPane,
isFirstMessageByAuthor = isFirstMessageByAuthor,
isLastMessageByAuthor = isLastMessageByAuthor,
movableSharedElementScope = movableSharedElementScope,
Expand All @@ -129,6 +137,7 @@ fun Message(
item: MessageItem,
roomName: String?,
isUserMe: Boolean,
isInPrimaryPane: Boolean,
isFirstMessageByAuthor: Boolean,
isLastMessageByAuthor: Boolean,
movableSharedElementScope: MovableSharedElementScope
Expand Down Expand Up @@ -162,8 +171,9 @@ fun Message(
roomName?.let {
onAuthorClick(
Action.Navigation.GoToProfile(
roomName = it,
profileName = item.sender.name,
roomName = it
isInPrimaryPane = isInPrimaryPane,
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.tunjid.mutator.coroutines.toMutationStream
import com.tunjid.treenav.MultiStackNav
import com.tunjid.treenav.pop
import com.tunjid.treenav.push
import com.tunjid.treenav.swap
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
Expand Down Expand Up @@ -62,6 +63,7 @@ class ChatViewModel(
keySelector = Action::key
) {
when (val type = type()) {
is Action.UpdateInPrimaryPane -> type.flow.updateInPrimaryPaneMutations()
is Action.Navigation -> navigationRepository.navigationMutations(
type.flow
)
Expand Down Expand Up @@ -106,9 +108,13 @@ private fun chatLoadMutations(
copy(chats = it)
}

private fun Flow<Action.UpdateInPrimaryPane>.updateInPrimaryPaneMutations(): Flow<Mutation<State>> =
mapToMutation { copy(isInPrimaryPane = it.isInPrimaryPane) }

data class State(
val me: Profile? = null,
val room: ChatRoom? = null,
val isInPrimaryPane: Boolean = true,
val chats: List<MessageItem> = emptyList()
)

Expand All @@ -120,6 +126,11 @@ data class MessageItem(
sealed class Action(
val key: String
) {

data class UpdateInPrimaryPane(
val isInPrimaryPane: Boolean
) : Action("UpdateInPrimaryPane")

sealed class Navigation : Action("Navigation"), NavigationAction {
data object Pop : Navigation(), NavigationAction by navigationAction(
MultiStackNav::pop
Expand All @@ -128,14 +139,15 @@ sealed class Action(
data class GoToProfile(
val profileName: String,
val roomName: String,
val isInPrimaryPane: Boolean,
) : Navigation(), NavigationAction by navigationAction(
{
push(
SampleDestination.Profile(
profileName = profileName,
roomName = roomName,
)
val profileDestination = SampleDestination.Profile(
profileName = profileName,
roomName = roomName,
)
if (isInPrimaryPane) push(profileDestination)
else swap(profileDestination)
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.tunjid.demo.common.ui.chat

import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.coroutineScope
Expand Down Expand Up @@ -46,6 +47,13 @@ fun chatAdaptiveConfiguration(
state = viewModel.state.collectAsStateWithLifecycle().value,
onAction = viewModel.accept
)
LaunchedEffect(paneState.pane) {
viewModel.accept(
Action.UpdateInPrimaryPane(
isInPrimaryPane = paneState.pane == ThreePane.Primary
)
)
}
},
paneMapping = {
mapOf(
Expand Down
Loading
Loading