remove refresh icon and implement pull down to refresh
This commit is contained in:
@@ -134,7 +134,7 @@ fun FileBrowser(
|
||||
// Parent directory item
|
||||
if (canNavigateUp) {
|
||||
item {
|
||||
FileItem(
|
||||
FileItemCard(
|
||||
name = "..",
|
||||
size = "",
|
||||
isDirectory = true,
|
||||
@@ -145,7 +145,7 @@ fun FileBrowser(
|
||||
}
|
||||
|
||||
items(files) { file ->
|
||||
FileItem(
|
||||
FileItemCard(
|
||||
name = file.name,
|
||||
size = file.formattedSize,
|
||||
isIso = file.name.lowercase().endsWith(".iso"),
|
||||
@@ -164,7 +164,7 @@ fun FileBrowser(
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun FileItem(
|
||||
fun FileItemCard(
|
||||
name: String,
|
||||
size: String,
|
||||
isDirectory: Boolean = false,
|
||||
|
||||
@@ -5,18 +5,28 @@
|
||||
|
||||
package sh.sar.isodroid.ui.screens
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Album
|
||||
import androidx.compose.material.icons.filled.Download
|
||||
import androidx.compose.material.icons.filled.Eject
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
@@ -42,10 +52,9 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import sh.sar.isodroid.data.IsoFile
|
||||
import sh.sar.isodroid.data.MountOptions
|
||||
import sh.sar.isodroid.ui.components.CreateImgDialog
|
||||
import sh.sar.isodroid.ui.components.FileContextMenu
|
||||
import sh.sar.isodroid.ui.components.FileBrowser
|
||||
import sh.sar.isodroid.ui.components.FileItemCard
|
||||
import sh.sar.isodroid.ui.components.MountDialog
|
||||
import sh.sar.isodroid.ui.components.StatusCard
|
||||
import sh.sar.isodroid.viewmodel.MainViewModel
|
||||
@@ -66,6 +75,22 @@ fun MainScreen(
|
||||
var showCreateImgDialog by remember { mutableStateOf(false) }
|
||||
var contextMenuFile by remember { mutableStateOf<IsoFile?>(null) }
|
||||
|
||||
val pullToRefreshState = rememberPullToRefreshState()
|
||||
|
||||
// Handle pull-to-refresh
|
||||
if (pullToRefreshState.isRefreshing) {
|
||||
LaunchedEffect(true) {
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
// Stop refreshing when loading completes
|
||||
LaunchedEffect(uiState.isLoading) {
|
||||
if (!uiState.isLoading) {
|
||||
pullToRefreshState.endRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
// Show error messages
|
||||
LaunchedEffect(uiState.errorMessage) {
|
||||
uiState.errorMessage?.let { message ->
|
||||
@@ -104,12 +129,6 @@ fun MainScreen(
|
||||
contentDescription = "Create IMG"
|
||||
)
|
||||
}
|
||||
IconButton(onClick = { viewModel.refresh() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Refresh,
|
||||
contentDescription = "Refresh"
|
||||
)
|
||||
}
|
||||
IconButton(onClick = onNavigateToDownloads) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Download,
|
||||
@@ -147,45 +166,118 @@ fun MainScreen(
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.padding(16.dp)
|
||||
.nestedScroll(pullToRefreshState.nestedScrollConnection)
|
||||
) {
|
||||
StatusCard(
|
||||
mountStatus = uiState.mountStatus,
|
||||
rootAvailable = uiState.hasRoot,
|
||||
deviceSupported = uiState.isSupported,
|
||||
rootDenied = uiState.rootDenied,
|
||||
onRequestRoot = { viewModel.requestRootAccess() }
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
if (uiState.isLoading) {
|
||||
if (uiState.isLoading && !pullToRefreshState.isRefreshing) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
} else if (uiState.hasRoot == true && uiState.isSupported == true) {
|
||||
FileBrowser(
|
||||
files = uiState.isoFiles,
|
||||
currentPath = uiState.currentPath,
|
||||
onFileClick = { file ->
|
||||
selectedFile = file
|
||||
showMountDialog = true
|
||||
},
|
||||
onFileLongClick = { file ->
|
||||
contextMenuFile = file
|
||||
},
|
||||
onNavigateUp = { viewModel.navigateUp() },
|
||||
canNavigateUp = viewModel.canNavigateUp(),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
// Status card
|
||||
item {
|
||||
StatusCard(
|
||||
mountStatus = uiState.mountStatus,
|
||||
rootAvailable = uiState.hasRoot,
|
||||
deviceSupported = uiState.isSupported,
|
||||
rootDenied = uiState.rootDenied,
|
||||
onRequestRoot = { viewModel.requestRootAccess() }
|
||||
)
|
||||
}
|
||||
|
||||
// File browser content
|
||||
if (uiState.hasRoot == true && uiState.isSupported == true) {
|
||||
if (uiState.isoFiles.isEmpty()) {
|
||||
// Empty state
|
||||
item {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillParentMaxSize()
|
||||
.padding(32.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Album,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(64.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = "No ISO/IMG files found",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "Place ISO or IMG files in:\n${uiState.currentPath}",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
|
||||
textAlign = androidx.compose.ui.text.style.TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = "Tap + to create an empty IMG file\nChange directory in Settings",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f),
|
||||
textAlign = androidx.compose.ui.text.style.TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Parent directory navigation
|
||||
if (viewModel.canNavigateUp()) {
|
||||
item {
|
||||
FileItemCard(
|
||||
name = "..",
|
||||
size = "",
|
||||
isDirectory = true,
|
||||
onClick = { viewModel.navigateUp() },
|
||||
onLongClick = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// File list
|
||||
items(uiState.isoFiles) { file ->
|
||||
FileItemCard(
|
||||
name = file.name,
|
||||
size = file.formattedSize,
|
||||
isIso = file.name.lowercase().endsWith(".iso"),
|
||||
isImg = file.name.lowercase().endsWith(".img"),
|
||||
onClick = {
|
||||
selectedFile = file
|
||||
showMountDialog = true
|
||||
},
|
||||
onLongClick = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
contextMenuFile = file
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PullToRefreshContainer(
|
||||
state = pullToRefreshState,
|
||||
modifier = Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user