refactor: extract common part from the HomeTopBar and make component logic reusable

This commit is contained in:
2026-04-27 21:11:25 +02:00
parent afdd9b860f
commit 4c986432f6
7 changed files with 111 additions and 164 deletions

View File

@@ -1,102 +0,0 @@
package hu.bbara.purefin.ui.common
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Person
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.feature.search.SearchViewModel
@Composable
fun DefaultTopBar(
modifier: Modifier = Modifier,
searchViewModel: SearchViewModel = hiltViewModel(),
onProfileClick: () -> Unit = {},
onSettingsClick: () -> Unit = {},
onLogoutClick: () -> Unit = {},
) {
val scheme = MaterialTheme.colorScheme
val searchResult = searchViewModel.searchResult.collectAsState()
var isProfileMenuExpanded by remember { mutableStateOf(false) }
var isSearchExpanded by remember { mutableStateOf(false) }
Box(
modifier = modifier
.fillMaxWidth()
.background(scheme.background.copy(alpha = 0.95f))
.zIndex(1f)
) {
Box(
modifier = Modifier
.statusBarsPadding()
.padding(horizontal = 16.dp, vertical = 16.dp)
.fillMaxWidth(),
contentAlignment = Alignment.CenterEnd
) {
if (!isSearchExpanded) {
Box {
IconButton(
onClick = { isProfileMenuExpanded = true },
modifier = Modifier
.size(56.dp)
.clip(CircleShape),
) {
Icon(
imageVector = Icons.Outlined.Person,
contentDescription = "Profile",
modifier = Modifier.size(30.dp),
)
}
DropdownMenu(
expanded = isProfileMenuExpanded,
onDismissRequest = { isProfileMenuExpanded = false },
) {
DropdownMenuItem(
text = { Text("Profile") },
onClick = {
isProfileMenuExpanded = false
onProfileClick()
}
)
DropdownMenuItem(
text = { Text("Settings") },
onClick = {
isProfileMenuExpanded = false
onSettingsClick()
}
)
DropdownMenuItem(
text = { Text("Logout") },
onClick = {
isProfileMenuExpanded = false
onLogoutClick()
}
)
}
}
}
}
}
}

View File

@@ -3,6 +3,9 @@ package hu.bbara.purefin.ui.screen
import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform import androidx.compose.animation.ContentTransform
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@@ -26,9 +29,6 @@ import hu.bbara.purefin.ui.screen.home.HomeScreen
import hu.bbara.purefin.ui.screen.home.components.HomeNavItem import hu.bbara.purefin.ui.screen.home.components.HomeNavItem
import hu.bbara.purefin.ui.screen.libraries.LibrariesScreen import hu.bbara.purefin.ui.screen.libraries.LibrariesScreen
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
@Composable @Composable
fun AppScreen( fun AppScreen(
@@ -99,9 +99,6 @@ fun AppScreen(
LibrariesScreen( LibrariesScreen(
items = libraryNavItems, items = libraryNavItems,
onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.label) }, onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.label) },
onProfileClick = {},
onSettingsClick = {},
onLogoutClick = viewModel::logout,
selectedTab = selectedTab, selectedTab = selectedTab,
onTabSelected = onTabSelected, onTabSelected = onTabSelected,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()

View File

@@ -12,8 +12,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import hu.bbara.purefin.ui.model.MediaUiModel
import hu.bbara.purefin.feature.browse.home.LibraryItem import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.ui.model.MediaUiModel
import hu.bbara.purefin.ui.screen.AppBottomBar import hu.bbara.purefin.ui.screen.AppBottomBar
import hu.bbara.purefin.ui.screen.home.components.HomeContent import hu.bbara.purefin.ui.screen.home.components.HomeContent
import hu.bbara.purefin.ui.screen.home.components.HomeTopBar import hu.bbara.purefin.ui.screen.home.components.HomeTopBar

View File

@@ -0,0 +1,60 @@
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.ui.common.image.PurefinLogo
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DefaultTopBar(
actions: @Composable RowScope.() -> Unit
) {
val scheme = MaterialTheme.colorScheme
TopAppBar(
title = {
Row(
modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
PurefinLogo(
contentDescription = "Purefin",
modifier = Modifier.size(48.dp),
contentScale = ContentScale.Fit,
)
Text(
text = "PureFin",
fontSize = 32.sp,
fontWeight = FontWeight.Bold,
fontStyle = FontStyle.Italic,
color = scheme.onSecondary
)
}
},
actions = actions,
colors = TopAppBarDefaults.largeTopAppBarColors(
containerColor = scheme.background,
navigationIconContentColor = scheme.onSurface,
actionIconContentColor = scheme.onSurface,
titleContentColor = scheme.onSurface
),
modifier = Modifier.padding(end = 12.dp)
)
}

View File

@@ -1,7 +1,5 @@
package hu.bbara.purefin.ui.screen.home.components package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
@@ -10,63 +8,33 @@ import androidx.compose.material.icons.outlined.Person
import androidx.compose.material.icons.outlined.Search import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
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.layout.ContentScale
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.ui.common.image.PurefinLogo
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun HomeTopBar( fun HomeTopBar(
onSearchClick: () -> Unit, onSearchClick: () -> Unit,
onProfileClick: () -> Unit, onProfileClick: () -> Unit,
onSettingsClick: () -> Unit, onSettingsClick: () -> Unit,
onLogoutClick: () -> Unit, onLogoutClick: () -> Unit,
modifier: Modifier = Modifier,
) { ) {
val scheme = MaterialTheme.colorScheme val scheme = MaterialTheme.colorScheme
var isProfileMenuExpanded by remember { mutableStateOf(false) } var isProfileMenuExpanded by remember { mutableStateOf(false) }
TopAppBar( DefaultTopBar()
title = { {
Row(
modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
PurefinLogo(
contentDescription = "Purefin",
modifier = Modifier.size(48.dp),
contentScale = ContentScale.Fit,
)
Text(
text = "PureFin",
fontSize = 32.sp,
fontWeight = FontWeight.Bold,
fontStyle = FontStyle.Italic,
color = scheme.onSecondary
)
}
},
actions = {
IconButton( IconButton(
onClick = onSearchClick, onClick = onSearchClick,
colors = IconButtonColors( colors = IconButtonColors(
@@ -126,14 +94,5 @@ fun HomeTopBar(
} }
) )
} }
}, }
colors = TopAppBarDefaults.largeTopAppBarColors(
containerColor = scheme.background,
scrolledContainerColor = scheme.surface.copy(alpha = 0.96f),
navigationIconContentColor = scheme.onSurface,
actionIconContentColor = scheme.onSurface,
titleContentColor = scheme.onSurface
),
modifier = modifier
)
} }

View File

@@ -6,18 +6,15 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import hu.bbara.purefin.ui.common.DefaultTopBar
import hu.bbara.purefin.ui.screen.home.components.HomeNavItem
import hu.bbara.purefin.ui.screen.AppBottomBar import hu.bbara.purefin.ui.screen.AppBottomBar
import hu.bbara.purefin.ui.screen.home.components.HomeNavItem
import hu.bbara.purefin.ui.screen.libraries.components.LibrariesContent import hu.bbara.purefin.ui.screen.libraries.components.LibrariesContent
import hu.bbara.purefin.ui.screen.library.components.LibraryTopBar
@Composable @Composable
fun LibrariesScreen( fun LibrariesScreen(
items: List<HomeNavItem>, items: List<HomeNavItem>,
onLibrarySelected: (HomeNavItem) -> Unit, onLibrarySelected: (HomeNavItem) -> Unit,
onProfileClick: () -> Unit,
onSettingsClick: () -> Unit,
onLogoutClick: () -> Unit,
selectedTab: Int, selectedTab: Int,
onTabSelected: (Int) -> Unit, onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
@@ -27,10 +24,8 @@ fun LibrariesScreen(
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
contentColor = MaterialTheme.colorScheme.onBackground, contentColor = MaterialTheme.colorScheme.onBackground,
topBar = { topBar = {
DefaultTopBar( LibraryTopBar(
onProfileClick = onProfileClick, onSearchClick = {},
onSettingsClick = onSettingsClick,
onLogoutClick = onLogoutClick
) )
}, },
bottomBar = { bottomBar = {

View File

@@ -0,0 +1,38 @@
package hu.bbara.purefin.ui.screen.library.components
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar
@Composable
fun LibraryTopBar(
onSearchClick: () -> Unit,
) {
val scheme = MaterialTheme.colorScheme
DefaultTopBar {
IconButton(
onClick = onSearchClick,
colors = IconButtonColors(
containerColor = scheme.secondary,
contentColor = scheme.onSecondary,
disabledContainerColor = scheme.secondary,
disabledContentColor = scheme.onSecondary),
modifier = Modifier.size(50.dp),
) {
Icon(
imageVector = Icons.Outlined.Search,
contentDescription = "Search",
modifier = Modifier.size(30.dp),
)
}
}
}