@@ -12,17 +12,23 @@ import androidx.compose.foundation.layout.fillMaxSize
1212import androidx.compose.foundation.layout.height
1313import androidx.compose.foundation.layout.padding
1414import androidx.compose.foundation.lazy.LazyColumn
15+ import androidx.compose.foundation.pager.HorizontalPager
16+ import androidx.compose.foundation.pager.rememberPagerState
1517import androidx.compose.material.icons.Icons
1618import androidx.compose.material.icons.filled.Add
1719import androidx.compose.material.icons.filled.Info
1820import androidx.compose.material.icons.filled.Share
21+ import androidx.compose.material.icons.outlined.Inventory2
22+ import androidx.compose.material.icons.outlined.People
1923import androidx.compose.material3.Button
2024import androidx.compose.material3.CenterAlignedTopAppBar
2125import androidx.compose.material3.ExperimentalMaterial3Api
2226import androidx.compose.material3.Icon
2327import androidx.compose.material3.IconButton
2428import androidx.compose.material3.MaterialTheme
29+ import androidx.compose.material3.PrimaryTabRow
2530import androidx.compose.material3.Scaffold
31+ import androidx.compose.material3.Tab
2632import androidx.compose.material3.Text
2733import androidx.compose.material3.pulltorefresh.PullToRefreshBox
2834import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator
@@ -160,6 +166,7 @@ fun ExploreSkin(
160166) {
161167 val context = LocalContext .current
162168 val state = rememberPullToRefreshState()
169+ val scope = rememberCoroutineScope()
163170
164171 val statusMap by SkinDownloadQueue .status.collectAsState()
165172
@@ -185,6 +192,26 @@ fun ExploreSkin(
185192
186193 var isShowInfoDialog by remember { mutableStateOf(false ) }
187194
195+ // Tab definitions
196+ val tabTitles = listOf (
197+ stringResource(R .string.tab_built_in),
198+ stringResource(R .string.tab_community),
199+ )
200+ val tabIcons = listOf (
201+ Icons .Outlined .Inventory2 ,
202+ Icons .Outlined .People ,
203+ )
204+
205+ val pagerState = rememberPagerState(pageCount = { tabTitles.size })
206+
207+ // Filter skins based on selected tab
208+ val builtInSkins = remember(skinCollection) {
209+ skinCollection?.filter { it.isBuiltIn } ? : emptyList()
210+ }
211+ val communitySkins = remember(skinCollection) {
212+ skinCollection?.filter { ! it.isBuiltIn } ? : emptyList()
213+ }
214+
188215 Scaffold (
189216 topBar = {
190217 CenterAlignedTopAppBar (
@@ -225,66 +252,111 @@ fun ExploreSkin(
225252 )
226253 }
227254 ) { innerPadding ->
228- PullToRefreshBox (
229- isRefreshing = isRefreshing,
230- onRefresh = onRefresh,
231- state = state,
232- indicator = {
233- Indicator (
234- modifier = Modifier .align(Alignment .TopCenter ),
235- isRefreshing = isRefreshing,
236- containerColor = MaterialTheme .colorScheme.surface,
237- color = MaterialTheme .colorScheme.primary,
238- state = state
239- )
240- },
255+ Column (
241256 modifier = Modifier
242257 .padding(innerPadding)
243258 .fillMaxSize()
244259 ) {
245- skinCollection?.let {
246- LazyColumn (modifier = modifier) {
247- if (it.isEmpty() && ! isLoading) {
248- item {
249- Column (
250- modifier = Modifier
251- .fillMaxSize()
252- .padding(16 .dp),
253- horizontalAlignment = Alignment .CenterHorizontally ,
254- verticalArrangement = Arrangement .Center ,
255- ) {
256- Text (
257- text = stringResource(R .string.hi_there_is_no_skin_collection_for_now),
258- modifier = Modifier .padding(16 .dp),
259- style = MaterialTheme .typography.bodyLarge
260- )
261- Button (onClick = {
262- filePickerLauncher.launch(
263- arrayOf(" application/zip" , " application/x-zip-compressed" )
264- )
265- }) {
266- Text (
267- text = stringResource(R .string.try_to_import_from_zip),
268- style = MaterialTheme .typography.bodyLarge
269- )
260+ // Tab Row
261+ PrimaryTabRow (
262+ selectedTabIndex = pagerState.currentPage,
263+ ) {
264+ tabTitles.forEachIndexed { index, title ->
265+ Tab (
266+ selected = pagerState.currentPage == index,
267+ onClick = {
268+ scope.launch { pagerState.animateScrollToPage(index) }
269+ },
270+ text = {
271+ Text (
272+ text = title,
273+ style = MaterialTheme .typography.labelLarge,
274+ fontWeight = if (pagerState.currentPage == index)
275+ FontWeight .Bold else FontWeight .Normal ,
276+ )
277+ },
278+ icon = {
279+ Icon (
280+ imageVector = tabIcons[index],
281+ contentDescription = title,
282+ )
283+ },
284+ )
285+ }
286+ }
287+
288+ // Pager content
289+ PullToRefreshBox (
290+ isRefreshing = isRefreshing,
291+ onRefresh = onRefresh,
292+ state = state,
293+ indicator = {
294+ Indicator (
295+ modifier = Modifier .align(Alignment .TopCenter ),
296+ isRefreshing = isRefreshing,
297+ containerColor = MaterialTheme .colorScheme.surface,
298+ color = MaterialTheme .colorScheme.primary,
299+ state = state
300+ )
301+ },
302+ modifier = Modifier .fillMaxSize()
303+ ) {
304+ HorizontalPager (
305+ state = pagerState,
306+ modifier = Modifier .fillMaxSize(),
307+ ) { page ->
308+ val currentSkins = if (page == 0 ) builtInSkins else communitySkins
309+
310+ if (skinCollection != null ) {
311+ LazyColumn (modifier = modifier.fillMaxSize()) {
312+ if (currentSkins.isEmpty() && ! isLoading) {
313+ item {
314+ Column (
315+ modifier = Modifier
316+ .fillMaxSize()
317+ .padding(16 .dp),
318+ horizontalAlignment = Alignment .CenterHorizontally ,
319+ verticalArrangement = Arrangement .Center ,
320+ ) {
321+ Text (
322+ text = stringResource(R .string.hi_there_is_no_skin_collection_for_now),
323+ modifier = Modifier .padding(16 .dp),
324+ style = MaterialTheme .typography.bodyLarge
325+ )
326+ Button (onClick = {
327+ filePickerLauncher.launch(
328+ arrayOf(
329+ " application/zip" ,
330+ " application/x-zip-compressed"
331+ )
332+ )
333+ }) {
334+ Text (
335+ text = stringResource(R .string.try_to_import_from_zip),
336+ style = MaterialTheme .typography.bodyLarge
337+ )
338+ }
339+ }
270340 }
271341 }
272- }
273- }
274342
275- items(it.size) { index ->
276- val collection = it[index]
277- val st = statusMap[collection.packageName] ? : DownloadStatus .Idle
278- val queuePos = SkinDownloadQueue .queuePositionOf(collection.packageName)
343+ items(currentSkins.size) { index ->
344+ val collection = currentSkins[index]
345+ val st =
346+ statusMap[collection.packageName] ? : DownloadStatus .Idle
347+ val queuePos =
348+ SkinDownloadQueue .queuePositionOf(collection.packageName)
279349
280- ExploreItem (
281- collection = collection,
282- isInstalled = isInstalled(collection.packageName),
283- st = st,
284- queuePos = queuePos,
285- )
350+ ExploreItem (
351+ collection = collection,
352+ isInstalled = isInstalled(collection.packageName),
353+ st = st,
354+ queuePos = queuePos,
355+ )
356+ }
357+ item { Spacer (modifier = Modifier .height(90 .dp)) }
358+ }
286359 }
287- item { Spacer (modifier = Modifier .height(90 .dp)) }
288360 }
289361 }
290362 }
0 commit comments