Feat(ToolStore and Tools): Support query by tool name or keywords
This commit is contained in:
@@ -20,12 +20,19 @@ interface ToolDao {
|
|||||||
@Delete
|
@Delete
|
||||||
suspend fun deleteTool(tool: ToolEntity)
|
suspend fun deleteTool(tool: ToolEntity)
|
||||||
|
|
||||||
@Query("SELECT * FROM tools WHERE id = :id")
|
@Query("SELECT * FROM tools " +
|
||||||
|
"WHERE id = :id")
|
||||||
fun selectToolById(id: Long): Flow<ToolEntity?>
|
fun selectToolById(id: Long): Flow<ToolEntity?>
|
||||||
|
|
||||||
@Query("SELECT * FROM tools ORDER BY updateTime DESC")
|
@Query("SELECT * FROM tools " +
|
||||||
fun selectAllTools(): Flow<List<ToolEntity>>
|
"WHERE :searchValue = '' " +
|
||||||
|
"OR name LIKE '%' || :searchValue || '%' COLLATE NOCASE " +
|
||||||
|
"OR keywords LIKE '%\"%' || :searchValue || '%\"%' COLLATE NOCASE " +
|
||||||
|
"ORDER BY updateTime DESC")
|
||||||
|
fun selectAllTools(searchValue: String): Flow<List<ToolEntity>>
|
||||||
|
|
||||||
@Query("SELECT * FROM tools WHERE authorUsername = :username and toolId = :toolId LIMIT 1")
|
@Query("SELECT * FROM tools " +
|
||||||
|
"WHERE authorUsername = :username " +
|
||||||
|
"and toolId = :toolId LIMIT 1")
|
||||||
fun selectToolByUsernameAndToolId(username: String, toolId: String): Flow<ToolEntity?>
|
fun selectToolByUsernameAndToolId(username: String, toolId: String): Flow<ToolEntity?>
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,9 @@ fun OxygenNavHost(
|
|||||||
appState: OxygenAppState,
|
appState: OxygenAppState,
|
||||||
onShowSnackbar: suspend (message: String, action: String?) -> Boolean,
|
onShowSnackbar: suspend (message: String, action: String?) -> Boolean,
|
||||||
startDestination: String,
|
startDestination: String,
|
||||||
isVertical: Boolean
|
isVertical: Boolean,
|
||||||
|
searchValue: String,
|
||||||
|
searchCount: Int
|
||||||
) {
|
) {
|
||||||
val navController = appState.navController
|
val navController = appState.navController
|
||||||
NavHost(
|
NavHost(
|
||||||
@@ -19,9 +21,6 @@ fun OxygenNavHost(
|
|||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = startDestination
|
startDestination = startDestination
|
||||||
) {
|
) {
|
||||||
searchScreen(
|
|
||||||
onBackClick = navController::popBackStack
|
|
||||||
)
|
|
||||||
aboutScreen(
|
aboutScreen(
|
||||||
onBackClick = navController::popBackStack,
|
onBackClick = navController::popBackStack,
|
||||||
onNavigateToLibraries = navController::navigateToLibraries
|
onNavigateToLibraries = navController::navigateToLibraries
|
||||||
@@ -31,10 +30,13 @@ fun OxygenNavHost(
|
|||||||
)
|
)
|
||||||
toolStoreScreen(
|
toolStoreScreen(
|
||||||
isVertical = isVertical,
|
isVertical = isVertical,
|
||||||
|
searchValue = searchValue,
|
||||||
|
searchCount = searchCount,
|
||||||
onNavigateToToolView = navController::navigateToToolView
|
onNavigateToToolView = navController::navigateToToolView
|
||||||
)
|
)
|
||||||
toolsScreen(
|
toolsScreen(
|
||||||
isVertical = isVertical,
|
isVertical = isVertical,
|
||||||
|
searchValue = searchValue,
|
||||||
onShowSnackbar = onShowSnackbar,
|
onShowSnackbar = onShowSnackbar,
|
||||||
onNavigateToToolView = navController::navigateToToolView,
|
onNavigateToToolView = navController::navigateToToolView,
|
||||||
onNavigateToToolStore = { appState.navigateToTopLevelDestination(TopLevelDestination.ToolStore) }
|
onNavigateToToolStore = { appState.navigateToTopLevelDestination(TopLevelDestination.ToolStore) }
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package top.fatweb.oxygen.toolbox.navigation
|
|
||||||
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.NavGraphBuilder
|
|
||||||
import androidx.navigation.NavOptions
|
|
||||||
import androidx.navigation.compose.composable
|
|
||||||
import top.fatweb.oxygen.toolbox.ui.search.SearchRoute
|
|
||||||
|
|
||||||
const val SEARCH_ROUTE = "search_route"
|
|
||||||
|
|
||||||
fun NavController.navigateToSearch(navOptions: NavOptions? = null) =
|
|
||||||
navigate(SEARCH_ROUTE, navOptions)
|
|
||||||
|
|
||||||
fun NavGraphBuilder.searchScreen(
|
|
||||||
onBackClick: () -> Unit
|
|
||||||
) {
|
|
||||||
composable(
|
|
||||||
route = SEARCH_ROUTE
|
|
||||||
) {
|
|
||||||
SearchRoute(onBackClick = onBackClick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,8 @@ fun NavController.navigateToToolStore(navOptions: NavOptions? = null) =
|
|||||||
|
|
||||||
fun NavGraphBuilder.toolStoreScreen(
|
fun NavGraphBuilder.toolStoreScreen(
|
||||||
isVertical: Boolean,
|
isVertical: Boolean,
|
||||||
|
searchValue: String,
|
||||||
|
searchCount: Int,
|
||||||
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit
|
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
composable(
|
composable(
|
||||||
@@ -41,6 +43,8 @@ fun NavGraphBuilder.toolStoreScreen(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
ToolStoreRoute(
|
ToolStoreRoute(
|
||||||
|
searchValue = searchValue,
|
||||||
|
searchCount = searchCount,
|
||||||
onNavigateToToolView = onNavigateToToolView
|
onNavigateToToolView = onNavigateToToolView
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ fun NavController.navigateToTools(navOptions: NavOptions) = navigate(TOOLS_ROUTE
|
|||||||
|
|
||||||
fun NavGraphBuilder.toolsScreen(
|
fun NavGraphBuilder.toolsScreen(
|
||||||
isVertical: Boolean,
|
isVertical: Boolean,
|
||||||
|
searchValue: String,
|
||||||
onShowSnackbar: suspend (message: String, action: String?) -> Boolean,
|
onShowSnackbar: suspend (message: String, action: String?) -> Boolean,
|
||||||
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit,
|
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit,
|
||||||
onNavigateToToolStore: () -> Unit
|
onNavigateToToolStore: () -> Unit
|
||||||
@@ -50,6 +51,7 @@ fun NavGraphBuilder.toolsScreen(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
ToolsRoute(
|
ToolsRoute(
|
||||||
|
searchValue = searchValue,
|
||||||
onShowSnackbar = onShowSnackbar,
|
onShowSnackbar = onShowSnackbar,
|
||||||
onNavigateToToolView = onNavigateToToolView,
|
onNavigateToToolView = onNavigateToToolView,
|
||||||
onNavigateToToolStore = onNavigateToToolStore
|
onNavigateToToolStore = onNavigateToToolStore
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
|
|||||||
interface ToolRepository {
|
interface ToolRepository {
|
||||||
val toolViewTemplate: Flow<String>
|
val toolViewTemplate: Flow<String>
|
||||||
|
|
||||||
fun getAllToolsStream(): Flow<List<ToolEntity>>
|
fun getAllToolsStream(searchValue: String): Flow<List<ToolEntity>>
|
||||||
|
|
||||||
fun getToolById(id: Long): Flow<ToolEntity?>
|
fun getToolById(id: Long): Flow<ToolEntity?>
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ class OfflineToolRepository @Inject constructor(
|
|||||||
override val toolViewTemplate: Flow<String>
|
override val toolViewTemplate: Flow<String>
|
||||||
get() = toolDataSource.toolViewTemplate
|
get() = toolDataSource.toolViewTemplate
|
||||||
|
|
||||||
override fun getAllToolsStream(): Flow<List<ToolEntity>> =
|
override fun getAllToolsStream(searchValue: String): Flow<List<ToolEntity>> =
|
||||||
toolDao.selectAllTools()
|
toolDao.selectAllTools(searchValue)
|
||||||
|
|
||||||
override fun getToolById(id: Long): Flow<ToolEntity?> =
|
override fun getToolById(id: Long): Flow<ToolEntity?> =
|
||||||
toolDao.selectToolById(id)
|
toolDao.selectToolById(id)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import androidx.compose.material3.TopAppBarDefaults
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
@@ -52,6 +53,7 @@ import top.fatweb.oxygen.toolbox.ui.component.OxygenNavigationBarItem
|
|||||||
import top.fatweb.oxygen.toolbox.ui.component.OxygenNavigationRail
|
import top.fatweb.oxygen.toolbox.ui.component.OxygenNavigationRail
|
||||||
import top.fatweb.oxygen.toolbox.ui.component.OxygenNavigationRailItem
|
import top.fatweb.oxygen.toolbox.ui.component.OxygenNavigationRailItem
|
||||||
import top.fatweb.oxygen.toolbox.ui.component.OxygenTopAppBar
|
import top.fatweb.oxygen.toolbox.ui.component.OxygenTopAppBar
|
||||||
|
import top.fatweb.oxygen.toolbox.ui.component.SearchButtonPosition
|
||||||
import top.fatweb.oxygen.toolbox.ui.settings.SettingsDialog
|
import top.fatweb.oxygen.toolbox.ui.settings.SettingsDialog
|
||||||
import top.fatweb.oxygen.toolbox.ui.theme.GradientColors
|
import top.fatweb.oxygen.toolbox.ui.theme.GradientColors
|
||||||
import top.fatweb.oxygen.toolbox.ui.theme.LocalGradientColors
|
import top.fatweb.oxygen.toolbox.ui.theme.LocalGradientColors
|
||||||
@@ -79,6 +81,20 @@ fun OxygenApp(appState: OxygenAppState) {
|
|||||||
|
|
||||||
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
|
|
||||||
|
var activeSearch by remember { mutableStateOf(false) }
|
||||||
|
var searchValue by remember { mutableStateOf("") }
|
||||||
|
var searchCount by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
|
LaunchedEffect(destination) {
|
||||||
|
activeSearch = false
|
||||||
|
searchValue = ""
|
||||||
|
if (searchCount == 0) {
|
||||||
|
searchCount++
|
||||||
|
} else {
|
||||||
|
searchCount = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(isOffline) {
|
LaunchedEffect(isOffline) {
|
||||||
if (isOffline) {
|
if (isOffline) {
|
||||||
snackbarHostState.showSnackbar(
|
snackbarHostState.showSnackbar(
|
||||||
@@ -152,12 +168,26 @@ fun OxygenApp(appState: OxygenAppState) {
|
|||||||
navigationIconContentDescription = stringResource(R.string.feature_settings_top_app_bar_navigation_icon_description),
|
navigationIconContentDescription = stringResource(R.string.feature_settings_top_app_bar_navigation_icon_description),
|
||||||
actionIcon = OxygenIcons.MoreVert,
|
actionIcon = OxygenIcons.MoreVert,
|
||||||
actionIconContentDescription = stringResource(R.string.feature_settings_top_app_bar_action_icon_description),
|
actionIconContentDescription = stringResource(R.string.feature_settings_top_app_bar_action_icon_description),
|
||||||
|
activeSearch = activeSearch,
|
||||||
|
searchButtonPosition = SearchButtonPosition.Navigation,
|
||||||
|
query = searchValue,
|
||||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
|
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
scrolledContainerColor = Color.Transparent
|
scrolledContainerColor = Color.Transparent
|
||||||
),
|
),
|
||||||
onNavigationClick = { appState.navigateToSearch() },
|
onNavigationClick = { activeSearch = true },
|
||||||
onActionClick = { showSettingsDialog = true }
|
onActionClick = { showSettingsDialog = true },
|
||||||
|
onQueryChange = {
|
||||||
|
searchValue = it
|
||||||
|
},
|
||||||
|
onSearch = {
|
||||||
|
searchCount++
|
||||||
|
},
|
||||||
|
onCancelSearch = {
|
||||||
|
searchValue = ""
|
||||||
|
activeSearch = false
|
||||||
|
searchCount = 0
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +204,9 @@ fun OxygenApp(appState: OxygenAppState) {
|
|||||||
LaunchPageConfig.Tools -> TOOLS_ROUTE
|
LaunchPageConfig.Tools -> TOOLS_ROUTE
|
||||||
LaunchPageConfig.Star -> STAR_ROUTE
|
LaunchPageConfig.Star -> STAR_ROUTE
|
||||||
},
|
},
|
||||||
isVertical = appState.shouldShowBottomBar
|
isVertical = appState.shouldShowBottomBar,
|
||||||
|
searchValue = searchValue,
|
||||||
|
searchCount = searchCount
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import top.fatweb.oxygen.toolbox.navigation.TOOL_STORE_ROUTE
|
|||||||
import top.fatweb.oxygen.toolbox.navigation.TopLevelDestination
|
import top.fatweb.oxygen.toolbox.navigation.TopLevelDestination
|
||||||
import top.fatweb.oxygen.toolbox.navigation.navigateToAbout
|
import top.fatweb.oxygen.toolbox.navigation.navigateToAbout
|
||||||
import top.fatweb.oxygen.toolbox.navigation.navigateToLibraries
|
import top.fatweb.oxygen.toolbox.navigation.navigateToLibraries
|
||||||
import top.fatweb.oxygen.toolbox.navigation.navigateToSearch
|
|
||||||
import top.fatweb.oxygen.toolbox.navigation.navigateToStar
|
import top.fatweb.oxygen.toolbox.navigation.navigateToStar
|
||||||
import top.fatweb.oxygen.toolbox.navigation.navigateToToolStore
|
import top.fatweb.oxygen.toolbox.navigation.navigateToToolStore
|
||||||
import top.fatweb.oxygen.toolbox.navigation.navigateToTools
|
import top.fatweb.oxygen.toolbox.navigation.navigateToTools
|
||||||
@@ -119,8 +118,6 @@ class OxygenAppState(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun navigateToSearch() = navController.navigateToSearch()
|
|
||||||
|
|
||||||
fun navigateToLibraries() = navController.navigateToLibraries()
|
fun navigateToLibraries() = navController.navigateToLibraries()
|
||||||
|
|
||||||
fun navigateToAbout() = navController.navigateToAbout()
|
fun navigateToAbout() = navController.navigateToAbout()
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ fun OxygenTopAppBar(
|
|||||||
actionIcon: ImageVector? = null,
|
actionIcon: ImageVector? = null,
|
||||||
actionIconContentDescription: String? = null,
|
actionIconContentDescription: String? = null,
|
||||||
activeSearch: Boolean = false,
|
activeSearch: Boolean = false,
|
||||||
|
searchButtonPosition: SearchButtonPosition = SearchButtonPosition.Action,
|
||||||
query: String = "",
|
query: String = "",
|
||||||
colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(),
|
colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(),
|
||||||
onNavigationClick: () -> Unit = {},
|
onNavigationClick: () -> Unit = {},
|
||||||
@@ -122,7 +123,15 @@ fun OxygenTopAppBar(
|
|||||||
else title()
|
else title()
|
||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
navigationIcon?.let {
|
if (activeSearch && searchButtonPosition == SearchButtonPosition.Navigation) IconButton(
|
||||||
|
onClick = onCancelSearch
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = OxygenIcons.Close,
|
||||||
|
contentDescription = stringResource(R.string.core_close)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else navigationIcon?.let {
|
||||||
IconButton(onClick = onNavigationClick) {
|
IconButton(onClick = onNavigationClick) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = navigationIcon,
|
imageVector = navigationIcon,
|
||||||
@@ -133,7 +142,9 @@ fun OxygenTopAppBar(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
if (activeSearch) IconButton(onClick = onCancelSearch) {
|
if (activeSearch && searchButtonPosition == SearchButtonPosition.Action) IconButton(
|
||||||
|
onClick = onCancelSearch
|
||||||
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = OxygenIcons.Close,
|
imageVector = OxygenIcons.Close,
|
||||||
contentDescription = stringResource(R.string.core_close)
|
contentDescription = stringResource(R.string.core_close)
|
||||||
@@ -154,6 +165,10 @@ fun OxygenTopAppBar(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SearchButtonPosition {
|
||||||
|
Navigation, Action
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@OxygenPreviews
|
@OxygenPreviews
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package top.fatweb.oxygen.toolbox.ui.search
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
internal fun SearchRoute(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onBackClick: () -> Unit,
|
|
||||||
// searchViewmodel: SearchViewModel = hiltViewModel()
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
IconButton(onClick = onBackClick) {
|
|
||||||
Icon(imageVector = OxygenIcons.Back, contentDescription = null)
|
|
||||||
}
|
|
||||||
Text("Search")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package top.fatweb.oxygen.toolbox.ui.search
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@HiltViewModel
|
|
||||||
class SearchViewModel @Inject constructor(
|
|
||||||
) : ViewModel()
|
|
||||||
@@ -37,6 +37,7 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -64,11 +65,17 @@ import top.fatweb.oxygen.toolbox.ui.component.scrollbar.scrollbarState
|
|||||||
internal fun ToolStoreRoute(
|
internal fun ToolStoreRoute(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: ToolStoreViewModel = hiltViewModel(),
|
viewModel: ToolStoreViewModel = hiltViewModel(),
|
||||||
|
searchValue: String,
|
||||||
|
searchCount: Int,
|
||||||
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit,
|
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
val toolStorePagingItems = viewModel.storeData.collectAsLazyPagingItems()
|
val toolStorePagingItems = viewModel.storeData.collectAsLazyPagingItems()
|
||||||
val installInfo by viewModel.installInfo.collectAsState()
|
val installInfo by viewModel.installInfo.collectAsState()
|
||||||
|
|
||||||
|
LaunchedEffect(searchCount) {
|
||||||
|
viewModel.onSearchValueChange(searchValue)
|
||||||
|
}
|
||||||
|
|
||||||
ToolStoreScreen(
|
ToolStoreScreen(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onNavigateToToolView = onNavigateToToolView,
|
onNavigateToToolView = onNavigateToToolView,
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ class ToolStoreViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onSearchValueChange(value: String) {
|
||||||
|
savedStateHandle[SEARCH_VALUE] = value
|
||||||
|
}
|
||||||
|
|
||||||
fun changeInstallInfo(
|
fun changeInstallInfo(
|
||||||
status: ToolStoreUiState.InstallInfo.Status = installInfo.value.status,
|
status: ToolStoreUiState.InstallInfo.Status = installInfo.value.status,
|
||||||
type: ToolStoreUiState.InstallInfo.Type = installInfo.value.type
|
type: ToolStoreUiState.InstallInfo.Type = installInfo.value.type
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import androidx.compose.material3.ModalBottomSheet
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
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
|
||||||
@@ -67,12 +68,17 @@ import top.fatweb.oxygen.toolbox.ui.util.ResourcesUtils
|
|||||||
internal fun ToolsRoute(
|
internal fun ToolsRoute(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: ToolsScreenViewModel = hiltViewModel(),
|
viewModel: ToolsScreenViewModel = hiltViewModel(),
|
||||||
|
searchValue: String,
|
||||||
onShowSnackbar: suspend (message: String, action: String?) -> Boolean,
|
onShowSnackbar: suspend (message: String, action: String?) -> Boolean,
|
||||||
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit,
|
onNavigateToToolView: (username: String, toolId: String, preview: Boolean) -> Unit,
|
||||||
onNavigateToToolStore: () -> Unit
|
onNavigateToToolStore: () -> Unit
|
||||||
) {
|
) {
|
||||||
val toolsScreenUiStateState by viewModel.toolsScreenUiState.collectAsStateWithLifecycle()
|
val toolsScreenUiStateState by viewModel.toolsScreenUiState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
LaunchedEffect(searchValue) {
|
||||||
|
viewModel.onSearchValueChange(searchValue)
|
||||||
|
}
|
||||||
|
|
||||||
ToolsScreen(
|
ToolsScreen(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onShowSnackbar = onShowSnackbar,
|
onShowSnackbar = onShowSnackbar,
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import androidx.lifecycle.SavedStateHandle
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -19,24 +21,30 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
class ToolsScreenViewModel @Inject constructor(
|
class ToolsScreenViewModel @Inject constructor(
|
||||||
private val storeRepository: StoreRepository,
|
private val storeRepository: StoreRepository,
|
||||||
private val toolRepository: ToolRepository,
|
private val toolRepository: ToolRepository,
|
||||||
savedStateHandle: SavedStateHandle
|
private val savedStateHandle: SavedStateHandle
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val searchValue = savedStateHandle.getStateFlow(SEARCH_VALUE, "")
|
private val searchValue = savedStateHandle.getStateFlow(SEARCH_VALUE, "")
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val toolsScreenUiState: StateFlow<ToolsScreenUiState> =
|
val toolsScreenUiState: StateFlow<ToolsScreenUiState> =
|
||||||
toolRepository.getAllToolsStream()
|
searchValue.flatMapLatest { searchValue ->
|
||||||
.map {
|
toolRepository.getAllToolsStream(searchValue).map {
|
||||||
if (it.isEmpty()) {
|
if (it.isEmpty()) {
|
||||||
ToolsScreenUiState.Nothing
|
ToolsScreenUiState.Nothing
|
||||||
} else {
|
} else {
|
||||||
ToolsScreenUiState.Success(it)
|
ToolsScreenUiState.Success(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.stateIn(
|
}.stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
initialValue = ToolsScreenUiState.Loading,
|
initialValue = ToolsScreenUiState.Loading,
|
||||||
started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds)
|
started = SharingStarted.WhileSubscribed(5.seconds.inWholeMilliseconds)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
fun onSearchValueChange(value: String) {
|
||||||
|
savedStateHandle[SEARCH_VALUE] = value
|
||||||
|
}
|
||||||
|
|
||||||
fun uninstall(tool: ToolEntity) {
|
fun uninstall(tool: ToolEntity) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|||||||
Reference in New Issue
Block a user