@@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.padding
2727import androidx.compose.foundation.layout.size
2828import androidx.compose.foundation.layout.systemBars
2929import androidx.compose.foundation.layout.union
30+ import androidx.compose.foundation.layout.wrapContentSize
3031import androidx.compose.foundation.pager.HorizontalPager
3132import androidx.compose.foundation.pager.rememberPagerState
3233import androidx.compose.foundation.shape.CircleShape
@@ -42,6 +43,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
4243import androidx.compose.material3.Icon
4344import androidx.compose.material3.MaterialTheme
4445import androidx.compose.material3.MenuDefaults
46+ import androidx.compose.material3.PrimaryScrollableTabRow
4547import androidx.compose.material3.PrimaryTabRow
4648import androidx.compose.material3.Surface
4749import androidx.compose.material3.Tab
@@ -82,7 +84,6 @@ import com.imashnake.animite.core.extensions.crossfadeModel
8284import com.imashnake.animite.core.extensions.horizontalOnly
8385import com.imashnake.animite.core.extensions.maxHeight
8486import com.imashnake.animite.core.extensions.plus
85- import com.imashnake.animite.core.ui.FallbackMessage
8687import com.imashnake.animite.core.ui.LocalPaddings
8788import com.imashnake.animite.core.ui.NestedScrollableContent
8889import com.imashnake.animite.core.ui.ProgressIndicatorScreen
@@ -96,7 +97,6 @@ import com.imashnake.animite.settings.SettingsPage
9697import kotlinx.coroutines.launch
9798import me.saket.cascade.CascadeDropdownMenu
9899import me.saket.cascade.rememberCascadeState
99- import com.imashnake.animite.core.R as coreR
100100import com.imashnake.animite.navigation.R as navigationR
101101
102102private const val DROP_DOWN_ITEMS_COUNT = 2
@@ -155,9 +155,16 @@ fun ProfileScreen(
155155 contentDescription = " Avatar" ,
156156 modifier = Modifier
157157 .align(Alignment .BottomStart )
158- .padding(start = LocalPaddings .current.medium )
158+ .padding(start = LocalPaddings .current.large )
159159 .padding(allPaddingValues.horizontalOnly)
160- .size(100 .dp),
160+ .wrapContentSize()
161+ .maxHeight(100 .dp)
162+ .clip(
163+ RoundedCornerShape (
164+ topStart = LocalPaddings .current.small,
165+ topEnd = LocalPaddings .current.small,
166+ )
167+ ),
161168 )
162169 SettingsAndMore (
163170 onNavigateToSettings = onNavigateToSettings,
@@ -184,16 +191,6 @@ fun ProfileScreen(
184191 style = MaterialTheme .typography.titleLarge,
185192 overflow = TextOverflow .Ellipsis ,
186193 )
187- UserDescription (
188- description = description,
189- modifier = Modifier .maxHeight(
190- if (LocalConfiguration .current.orientation == Configuration .ORIENTATION_PORTRAIT ) {
191- dimensionResource(R .dimen.user_about_height)
192- } else {
193- dimensionResource(R .dimen.user_about_height_landscape)
194- }
195- )
196- )
197194 }
198195 UserTabs (
199196 user = this @run,
@@ -211,7 +208,16 @@ fun ProfileScreen(
211208 }
212209 else -> ProgressIndicatorScreen (Modifier .padding(allPaddingValues))
213210 }
214- else -> Login (Modifier .padding(allPaddingValues))
211+ else -> {
212+ SettingsIcon (
213+ onNavigateToSettings = onNavigateToSettings,
214+ modifier = Modifier
215+ .align(Alignment .TopEnd )
216+ .padding(LocalPaddings .current.large)
217+ .padding(allPaddingValues.copy(bottom = 0 .dp)),
218+ )
219+ Login (Modifier .padding(allPaddingValues))
220+ }
215221 }
216222
217223 if (isLogOutDialogShown)
@@ -228,6 +234,7 @@ fun ProfileScreen(
228234 }
229235}
230236
237+ // TODO: Properly parse the user description and add this back.
231238@Composable
232239private fun UserDescription (description : String? , modifier : Modifier = Modifier ) {
233240 description?.let {
@@ -266,37 +273,13 @@ private fun SettingsAndMore(
266273 targetValue = if (expanded) 10 else 50 ,
267274 label = " corner_radius_animation" ,
268275 )
269- val infiniteTransition = rememberInfiniteTransition(label = " settings_icon" )
270- val angle by infiniteTransition.animateFloat(
271- initialValue = 0f ,
272- targetValue = 360f ,
273- animationSpec = infiniteRepeatable(
274- animation = tween(10000 , easing = LinearEasing ),
275- repeatMode = RepeatMode .Restart
276- ),
277- label = " rotation"
278- )
279276
280277 Row (
281278 horizontalArrangement = Arrangement .spacedBy(LocalPaddings .current.small),
282279 verticalAlignment = Alignment .CenterVertically ,
283280 modifier = modifier.padding(LocalPaddings .current.large)
284281 ) {
285- Surface (
286- color = MaterialTheme .colorScheme.surfaceContainer,
287- shape = CircleShape
288- ) {
289- Icon (
290- imageVector = Icons .Rounded .Settings ,
291- contentDescription = stringResource(R .string.settings),
292- tint = MaterialTheme .colorScheme.primary,
293- modifier = Modifier
294- .clickable { onNavigateToSettings(SettingsPage ) }
295- .padding(LocalPaddings .current.small)
296- .size(LocalPaddings .current.medium)
297- .graphicsLayer { rotationZ = angle }
298- )
299- }
282+ SettingsIcon (onNavigateToSettings = onNavigateToSettings)
300283
301284 Box {
302285 Surface (
@@ -367,6 +350,40 @@ private fun SettingsAndMore(
367350 }
368351}
369352
353+ @Composable
354+ fun SettingsIcon (
355+ onNavigateToSettings : (SettingsPage ) -> Unit ,
356+ modifier : Modifier = Modifier
357+ ) {
358+ val infiniteTransition = rememberInfiniteTransition(label = " settings_icon" )
359+ val angle by infiniteTransition.animateFloat(
360+ initialValue = 0f ,
361+ targetValue = 360f ,
362+ animationSpec = infiniteRepeatable(
363+ animation = tween(10000 , easing = LinearEasing ),
364+ repeatMode = RepeatMode .Restart
365+ ),
366+ label = " rotation"
367+ )
368+
369+ Surface (
370+ color = MaterialTheme .colorScheme.surfaceContainer,
371+ shape = CircleShape ,
372+ modifier = modifier,
373+ ) {
374+ Icon (
375+ imageVector = Icons .Rounded .Settings ,
376+ contentDescription = stringResource(R .string.settings),
377+ tint = MaterialTheme .colorScheme.primary,
378+ modifier = Modifier
379+ .clickable { onNavigateToSettings(SettingsPage ) }
380+ .padding(LocalPaddings .current.small)
381+ .size(LocalPaddings .current.medium)
382+ .graphicsLayer { rotationZ = angle }
383+ )
384+ }
385+ }
386+
370387@Composable
371388fun LogOutDialog (
372389 logOut : () -> Unit ,
@@ -414,37 +431,80 @@ private fun UserTabs(
414431 val onBackground = MaterialTheme .colorScheme.onBackground
415432 val horizontalContentPadding = contentPadding.horizontalOnly
416433
434+ var scrollableTabs by remember { mutableStateOf(false ) }
435+
417436 Column (modifier) {
418- PrimaryTabRow (
419- selectedTabIndex = pagerState.currentPage,
420- containerColor = MaterialTheme .colorScheme.background,
421- divider = {},
422- modifier = Modifier .padding(horizontalContentPadding)
423- ) {
424- titles.forEachIndexed { index, tab ->
425- Tab (
426- selected = pagerState.currentPage == index,
427- onClick = {
428- coroutineScope.launch { pagerState.animateScrollToPage(index) }
429- },
430- text = {
431- Text (
432- text = stringResource(tab.titleRes),
433- overflow = TextOverflow .Ellipsis ,
434- style = MaterialTheme .typography.bodyMedium,
435- color = onBackground.copy(
436- alpha = if (pagerState.currentPage == index) 1f else 0.5f
437- ),
438- maxLines = 1
439- )
440- },
441- modifier = Modifier
442- .padding(
443- horizontal = LocalPaddings .current.ultraTiny,
444- vertical = LocalPaddings .current.small
445- )
446- .clip(CircleShape )
447- )
437+ if (! scrollableTabs) {
438+ PrimaryTabRow (
439+ selectedTabIndex = pagerState.currentPage,
440+ containerColor = MaterialTheme .colorScheme.background,
441+ divider = {},
442+ modifier = Modifier .padding(horizontalContentPadding)
443+ ) {
444+ titles.forEachIndexed { index, tab ->
445+ Tab (
446+ selected = pagerState.currentPage == index,
447+ onClick = {
448+ coroutineScope.launch { pagerState.animateScrollToPage(index) }
449+ },
450+ text = {
451+ Text (
452+ text = stringResource(tab.titleRes),
453+ overflow = TextOverflow .Ellipsis ,
454+ style = MaterialTheme .typography.bodyMedium,
455+ color = onBackground.copy(
456+ alpha = if (pagerState.currentPage == index) 1f else 0.5f
457+ ),
458+ maxLines = 1 ,
459+ onTextLayout = { result ->
460+ if (result.hasVisualOverflow) {
461+ scrollableTabs = true
462+ }
463+ }
464+ )
465+ },
466+ modifier = Modifier
467+ .padding(
468+ horizontal = LocalPaddings .current.ultraTiny,
469+ vertical = LocalPaddings .current.small
470+ )
471+ .clip(CircleShape )
472+ )
473+ }
474+ }
475+ } else {
476+ PrimaryScrollableTabRow (
477+ selectedTabIndex = pagerState.currentPage,
478+ containerColor = MaterialTheme .colorScheme.background,
479+ edgePadding = LocalPaddings .current.small,
480+ divider = {},
481+ modifier = Modifier .padding(horizontalContentPadding)
482+ ) {
483+ titles.forEachIndexed { index, tab ->
484+ Tab (
485+ selected = pagerState.currentPage == index,
486+ onClick = {
487+ coroutineScope.launch { pagerState.animateScrollToPage(index) }
488+ },
489+ text = {
490+ Text (
491+ text = stringResource(tab.titleRes),
492+ overflow = TextOverflow .Ellipsis ,
493+ style = MaterialTheme .typography.bodyMedium,
494+ color = onBackground.copy(
495+ alpha = if (pagerState.currentPage == index) 1f else 0.5f
496+ ),
497+ maxLines = 1 ,
498+ )
499+ },
500+ modifier = Modifier
501+ .padding(
502+ horizontal = LocalPaddings .current.ultraTiny,
503+ vertical = LocalPaddings .current.small
504+ )
505+ .clip(CircleShape )
506+ )
507+ }
448508 }
449509 }
450510 HorizontalPager (
@@ -492,12 +552,6 @@ private fun UserTabs(
492552 animatedVisibilityScope = animatedVisibilityScope,
493553 contentPadding = tabContentPadding,
494554 )
495- else -> FallbackMessage (
496- message = stringResource(coreR.string.coming_soon),
497- modifier = Modifier
498- .align(Alignment .Center )
499- .padding(tabContentPadding)
500- )
501555 }
502556 }
503557 }
0 commit comments