Move search to TopAppBar & Android fullscreen toggle in Settings
This commit is contained in:
parent
b4e9578d5e
commit
da1f5d8fbb
1 changed files with 675 additions and 529 deletions
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
|
|
@ -21,8 +22,12 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -31,6 +36,8 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import mg.dot.feufaro.Platform
|
||||
import mg.dot.feufaro.getPlatform
|
||||
import mg.dot.feufaro.pdf.PrintSettings
|
||||
import mg.dot.feufaro.pdf.defaultPrintSettings
|
||||
import mg.dot.feufaro.pdf.rememberPdfExportAction
|
||||
|
|
@ -95,10 +102,11 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(isSearchActive) {
|
||||
if (isSearchActive) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
val isFullScreenEnabled by sharedScreenModel.isFullScreen.collectAsState()
|
||||
val fullscreenController = LocalFullscreenController.current
|
||||
|
||||
LaunchedEffect(isFullScreenEnabled) {
|
||||
fullscreenController(isFullScreenEnabled)
|
||||
}
|
||||
val fileContent = sharedScreenModel.fileContent.value ?: ""
|
||||
LaunchedEffect(Unit) {
|
||||
|
|
@ -213,16 +221,125 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
if (showSettingsDialog) {
|
||||
Settings(
|
||||
sharedScreenModel = sharedScreenModel,
|
||||
onDismissRequest = {
|
||||
showSettingsDialog = false
|
||||
}
|
||||
)
|
||||
}
|
||||
val favoritePaths by sharedScreenModel.playlistItems.collectAsState()
|
||||
Scaffold(contentWindowInsets = WindowInsets.safeDrawing, topBar = {
|
||||
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
|
||||
val platform = getPlatform()
|
||||
val isAndroid = platform.name.startsWith("Android")
|
||||
val topAppBarHeight = if (isAndroid) {
|
||||
if(maxWidth > maxHeight) {
|
||||
55.dp
|
||||
} else {
|
||||
if (isFullScreenEnabled) 70.dp else 80.dp
|
||||
}
|
||||
} else {
|
||||
55.dp
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
contentWindowInsets = if (isAndroid && !isFullScreenEnabled) {
|
||||
WindowInsets.safeDrawing.union(WindowInsets.displayCutout)
|
||||
} else {
|
||||
WindowInsets(0, 0, 0, 0)
|
||||
},
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
modifier = Modifier.height(55.dp).windowInsetsPadding(WindowInsets.safeDrawing),
|
||||
modifier = Modifier.height(topAppBarHeight)
|
||||
.windowInsetsPadding(
|
||||
if (isAndroid && !isFullScreenEnabled) {
|
||||
WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)
|
||||
} else {
|
||||
WindowInsets(0, 0, 0, 0)
|
||||
}
|
||||
),
|
||||
title = {
|
||||
AnimatedContent(
|
||||
targetState = isSearchActive,
|
||||
label = "SearchTransition"
|
||||
) { searchActive ->
|
||||
if (searchActive) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
BasicTextField(
|
||||
value = textInput,
|
||||
onValueChange = { newValue ->
|
||||
textInput = newValue
|
||||
sharedScreenModel.updateSearchTxt(newValue)
|
||||
},
|
||||
textStyle = LocalTextStyle.current.copy(
|
||||
color = Color.White,
|
||||
fontSize = 16.sp
|
||||
),
|
||||
singleLine = true,
|
||||
cursorBrush = SolidColor(Color.White),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(38.dp)
|
||||
.focusRequester(focusRequester)
|
||||
.background(
|
||||
color = Color.White.copy(alpha = 0.15f),
|
||||
shape = RoundedCornerShape(20.dp)
|
||||
),
|
||||
decorationBox = { innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = textInput,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
singleLine = true,
|
||||
visualTransformation = VisualTransformation.None,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "FFPM 1 Andriananahary ...",
|
||||
color = Color.White.copy(alpha = 0.5f),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Search,
|
||||
contentDescription = null,
|
||||
tint = Color.White.copy(alpha = 0.8f),
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (textInput.isNotEmpty()) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
textInput = ""
|
||||
sharedScreenModel.updateSearchTxt("")
|
||||
},
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Clear,
|
||||
contentDescription = "Effacer",
|
||||
tint = Color.White.copy(alpha = 0.8f),
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp),
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Color.Transparent,
|
||||
unfocusedContainerColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
|
||||
verticalArrangement = Arrangement.Center
|
||||
|
|
@ -237,6 +354,8 @@ fun MainScreenWithDrawer(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
scope.launch { drawerState.open() }
|
||||
|
|
@ -256,7 +375,7 @@ fun MainScreenWithDrawer(
|
|||
|
||||
Box(
|
||||
modifier = Modifier.padding(end = 16.dp),
|
||||
contentAlignment = Alignment.TopEnd
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
|
|
@ -302,7 +421,12 @@ fun MainScreenWithDrawer(
|
|||
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip(containerColor = Color.DarkGray, contentColor = Color.White) { Text(targetKeyLeft, fontSize = 12.sp) } },
|
||||
tooltip = {
|
||||
PlainTooltip(
|
||||
containerColor = Color.DarkGray,
|
||||
contentColor = Color.White
|
||||
) { Text(targetKeyLeft, fontSize = 12.sp) }
|
||||
},
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
IconButton(
|
||||
|
|
@ -324,7 +448,10 @@ fun MainScreenWithDrawer(
|
|||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip(containerColor = Color.DarkGray, contentColor = Color.White) { Text(text = tooltipText, fontSize = 12.sp) }
|
||||
PlainTooltip(
|
||||
containerColor = Color.DarkGray,
|
||||
contentColor = Color.White
|
||||
) { Text(text = tooltipText, fontSize = 12.sp) }
|
||||
},
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
|
|
@ -353,7 +480,12 @@ fun MainScreenWithDrawer(
|
|||
val targetKeyRight = keysOrder[(currentIndex + 1) % 12]
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip(containerColor = Color.DarkGray, contentColor = Color.White) { Text(targetKeyRight, fontSize = 12.sp) } },
|
||||
tooltip = {
|
||||
PlainTooltip(
|
||||
containerColor = Color.DarkGray,
|
||||
contentColor = Color.White
|
||||
) { Text(targetKeyRight, fontSize = 12.sp) }
|
||||
},
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
IconButton(
|
||||
|
|
@ -375,7 +507,10 @@ fun MainScreenWithDrawer(
|
|||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip(containerColor = Color.DarkGray, contentColor = Color.White) { Text(text = "Transposer en Do (C)", fontSize = 12.sp) }
|
||||
PlainTooltip(
|
||||
containerColor = Color.DarkGray,
|
||||
contentColor = Color.White
|
||||
) { Text(text = "Transposer en Do (C)", fontSize = 12.sp) }
|
||||
},
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
|
|
@ -389,7 +524,11 @@ fun MainScreenWithDrawer(
|
|||
modifier = Modifier.fillMaxWidth().height(36.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
border = BorderStroke(1.dp, Color(0xFFFFD700).copy(alpha = 0.5f)),
|
||||
colors = ButtonDefaults.outlinedButtonColors(contentColor = Color(0xFFFFD700))
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
contentColor = Color(
|
||||
0xFFFFD700
|
||||
)
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = "Transposer en C",
|
||||
|
|
@ -411,7 +550,7 @@ fun MainScreenWithDrawer(
|
|||
)
|
||||
}, floatingActionButton = {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth() //horizontalAlignment = Alignment.CenterHorizontally
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(5.dp), horizontalAlignment = Alignment.End,
|
||||
|
|
@ -451,7 +590,8 @@ fun MainScreenWithDrawer(
|
|||
onClick = {
|
||||
scope.launch {
|
||||
try {
|
||||
val initialDir = solfaScreenModel.fileRepository.getAppPublicFolder().absolutePath
|
||||
val initialDir =
|
||||
solfaScreenModel.fileRepository.getAppPublicFolder().absolutePath
|
||||
saveLauncher.launch(fileName, initialDir)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
|
|
@ -568,7 +708,7 @@ fun MainScreenWithDrawer(
|
|||
}, modifier = Modifier.alpha(0.45f)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if(showMidiCtrl) Icons.Filled.StopCircle else Icons.Filled.PlayCircle,
|
||||
imageVector = if (showMidiCtrl) Icons.Filled.StopCircle else Icons.Filled.PlayCircle,
|
||||
contentDescription = "Jouer",
|
||||
tint = Color.Blue
|
||||
)
|
||||
|
|
@ -597,7 +737,7 @@ fun MainScreenWithDrawer(
|
|||
Box(
|
||||
modifier = Modifier.fillMaxWidth(0.9f)
|
||||
) {
|
||||
if(player != null) {
|
||||
if (player != null) {
|
||||
MidiControlPanel(
|
||||
isPause = isPos,
|
||||
currentPos = currentPos,
|
||||
|
|
@ -619,7 +759,7 @@ fun MainScreenWithDrawer(
|
|||
mediaPlayer = player,
|
||||
onVolumeChange = { newVolume ->
|
||||
sharedScreenModel.setVolume(newVolume)
|
||||
// println("Changement volume $newVolume -l $volumelevel")
|
||||
// println("Changement volume $newVolume -l $volumelevel")
|
||||
},
|
||||
onVoiceVolumeChange = { index, volume ->
|
||||
player?.updateVoiceVolume(index, volume)
|
||||
|
|
@ -636,7 +776,11 @@ fun MainScreenWithDrawer(
|
|||
}) { paddingValues ->
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().padding(paddingValues).consumeWindowInsets(paddingValues).windowInsetsPadding(WindowInsets.safeDrawing.union(WindowInsets.ime))
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.consumeWindowInsets(paddingValues)
|
||||
/*.windowInsetsPadding(currentInsets.union(WindowInsets.ime))*/
|
||||
) {
|
||||
content(PaddingValues(0.dp))
|
||||
if (sharedScreenModel.isQRCodeVisible.value) {
|
||||
|
|
@ -644,29 +788,97 @@ fun MainScreenWithDrawer(
|
|||
sharedScreenModel = sharedScreenModel,
|
||||
fileRepository = solfaScreenModel.fileRepository
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = !isEditMode,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (isSearchActive) {
|
||||
sharedScreenModel.showSearchMenu(false)
|
||||
sharedScreenModel.updateSearchTxt("")
|
||||
textInput = ""
|
||||
} else {
|
||||
if (filteredSongs.isNotEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(0.75f).align(Alignment.TopCenter)
|
||||
.background(MaterialTheme.colorScheme.surface).border(
|
||||
1.dp,
|
||||
MaterialTheme.colorScheme.outlineVariant,
|
||||
shape = MaterialTheme.shapes.medium
|
||||
sharedScreenModel.showSearchMenu(true)
|
||||
scope.launch {
|
||||
delay(100)
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.size(56.dp)
|
||||
.alpha(0.6f)
|
||||
.background(
|
||||
color = Color.Blue,
|
||||
shape = CircleShape
|
||||
)
|
||||
) {
|
||||
if (filteredSongs.isNotEmpty()) {
|
||||
Icon(
|
||||
imageVector = if (isSearchActive) Icons.Default.Close else Icons.Default.Search,
|
||||
contentDescription = null,
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = isSearchActive && textInput.isNotEmpty(),
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.fillMaxWidth(0.85f)
|
||||
.padding(top = 8.dp)
|
||||
) {
|
||||
Card(
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
|
||||
) {
|
||||
val sortedSongs = remember(filteredSongs) {
|
||||
filteredSongs.sortedBy { item ->
|
||||
item.path.startsWith("assets://")
|
||||
}
|
||||
}
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
itemsIndexed(sortedSongs, key = {_, item -> item.path}) { index, item ->
|
||||
if (sortedSongs.isEmpty() && textInput.isNotEmpty()) {
|
||||
item {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = "Partition non trouvée pour \"$textInput\"",
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
},
|
||||
supportingContent = {
|
||||
Text(
|
||||
text = "Essayez un autre.",
|
||||
fontSize = 12.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.SearchOff,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
itemsIndexed(sortedSongs, key = { _, item -> item.path }) { index, item ->
|
||||
val isFavorite = favoritePaths.contains(item)
|
||||
ListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
imageVector = if(item.path.startsWith("assets://")) Icons.Default.ArrowDropDownCircle else Icons.Default.Folder,
|
||||
imageVector = if (item.path.startsWith("assets://")) Icons.Default.ArrowDropDownCircle else Icons.Default.Folder,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(30.dp)
|
||||
)
|
||||
|
|
@ -696,80 +908,14 @@ fun MainScreenWithDrawer(
|
|||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
content(paddingValues)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().fillMaxWidth(0.75f).align(Alignment.Center)
|
||||
.padding(paddingValues).windowInsetsPadding(WindowInsets.safeDrawing)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.TopEnd).padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Column(
|
||||
|
||||
) {
|
||||
|
||||
AnimatedContent(
|
||||
targetState = isSearchActive, label = "Search Transition"
|
||||
) { targetIsActive ->
|
||||
if (targetIsActive) {
|
||||
TextField(
|
||||
value = textInput,
|
||||
onValueChange = { newValue ->
|
||||
textInput = newValue
|
||||
sharedScreenModel.updateSearchTxt(newValue)
|
||||
},
|
||||
placeholder = {
|
||||
Text("... ...")
|
||||
},
|
||||
textStyle = MaterialTheme.typography.titleLarge.copy(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
),
|
||||
modifier = Modifier.focusRequester(focusRequester).fillMaxWidth(0.45f)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = Color.Gray,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
.alpha(0.6f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!isEditMode) {
|
||||
Column {
|
||||
IconButton(
|
||||
onClick = {
|
||||
sharedScreenModel.showSearchMenu(!isSearchActive)
|
||||
sharedScreenModel.updateSearchTxt("")
|
||||
textInput = ""
|
||||
}, modifier = Modifier.size(56.dp).alpha(0.45f).background(
|
||||
color = Color.Blue, shape = CircleShape
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
if(isSearchActive) Icons.Default.Close else Icons.Default.Search,
|
||||
contentDescription = "la recherche",
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val LocalFullscreenController = staticCompositionLocalOf<(Boolean) -> Unit> {
|
||||
{ _ -> }
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue