Implements AboutPage

This commit is contained in:
Hasinjato 2026-08-11 16:16:40 +03:00
parent 1f4c0d4829
commit 558ccbff4a
8 changed files with 245 additions and 44 deletions

View file

@ -13,6 +13,7 @@ plugins {
alias(libs.plugins.kotlinSerialization)
}
val appVersion = "1.0.0"
kotlin {
/*linuxX64 {
binaries {
@ -114,7 +115,7 @@ android {
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
versionName = appVersion
}
packaging {
resources {
@ -143,7 +144,8 @@ compose.desktop {
nativeDistributions {
targetFormats(TargetFormat.Exe, TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "Feufaro"
packageVersion = "1.0.0"
packageVersion = appVersion
jvmArgs("-Dapp.version=$appVersion")
modules("java.base", "java.desktop", "jdk.unsupported", "java.naming")
windows {

View file

@ -0,0 +1,32 @@
package mg.dot.feufaro.di
import android.content.pm.PackageManager
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
@Composable
actual fun rememberAppVersion(): String {
val context = LocalContext.current
return remember(context) {
try {
val pm = context.packageManager
val packageName = context.packageName
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
} else {
@Suppress("DEPRECATION")
pm.getPackageInfo(packageName, 0)
}
packageInfo.versionName ?: "0.0.0"
} catch (e: Exception) {
println("AppVersion Error: ${e.message}")
e.printStackTrace()
"0.0.0"
}
}
}

View file

@ -0,0 +1,6 @@
package mg.dot.feufaro.di
import androidx.compose.runtime.Composable
@Composable
expect fun rememberAppVersion(): String

View file

@ -0,0 +1,165 @@
package mg.dot.feufaro.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.filled.Email
import androidx.compose.material.icons.filled.Language
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import feufaro.composeapp.generated.resources.Res
import feufaro.composeapp.generated.resources.icon
import mg.dot.feufaro.di.rememberAppVersion
import mg.dot.feufaro.getPlatform
import org.jetbrains.compose.resources.painterResource
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AboutDialog(onDismiss: () -> Unit) {
val platform = getPlatform()
val isAndroid = platform.name.startsWith("Android")
val appVersion = rememberAppVersion()
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(
usePlatformDefaultWidth = false
)
) {
ElevatedCard(
modifier = Modifier
.fillMaxWidth(if(isAndroid) 0.9f else 0.3f)
.padding(16.dp),
shape = RoundedCornerShape(24.dp),
colors = CardDefaults.elevatedCardColors(
containerColor = MaterialTheme.colorScheme.surface
),
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 8.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.TopEnd) {
IconButton(
onClick = onDismiss,
modifier = Modifier.size(32.dp)
) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Fermer",
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
Surface(
modifier = Modifier.size(100.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f),
tonalElevation = 4.dp
) {
Image(
painter = painterResource(Res.drawable.icon),
contentDescription = "Logo Feufaro",
modifier = Modifier
.padding(12.dp)
.clip(CircleShape)
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Feufaro",
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.Bold),
color = MaterialTheme.colorScheme.primary
)
Surface(
color = MaterialTheme.colorScheme.secondaryContainer,
shape = RoundedCornerShape(12.dp),
modifier = Modifier.padding(top = 4.dp, bottom = 16.dp)
) {
Text(
text = "Version $appVersion",
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
}
Text(
text = "L'application pour lire, éditer et analyser vos partitions Solfa. Ecrivez et créez des harmonies, écoutez ses mélodies et organisez votre playlist en toute simplicité.",
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurfaceVariant,
lineHeight = 22.sp
)
Spacer(modifier = Modifier.height(24.dp))
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))
Spacer(modifier = Modifier.height(16.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
InfoIconItem(icon = Icons.Default.Language, label = "Site Web")
InfoIconItem(icon = Icons.Default.Email, label = "Contact")
InfoIconItem(icon = Icons.Default.Code, label = "Licence")
}
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "Fait avec <3",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f)
)
}
}
}
}
@Composable
fun InfoIconItem(icon: ImageVector, label: String) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
IconButton(
onClick = {
},
modifier = Modifier
.size(48.dp)
.background(MaterialTheme.colorScheme.surfaceVariant, CircleShape)
) {
Icon(
imageVector = icon,
contentDescription = label,
tint = MaterialTheme.colorScheme.primary
)
}
Spacer(modifier = Modifier.height(4.dp))
Text(
text = label,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}

View file

@ -11,6 +11,7 @@ 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.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
@ -28,18 +29,17 @@ import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
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
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -65,6 +65,7 @@ fun MainScreenWithDrawer(
) {
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
var showSettingsDialog by remember { mutableStateOf(false) }
var showAboutDialog by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val items by sharedScreenModel.drawerItems.collectAsState()
@ -215,6 +216,9 @@ fun MainScreenWithDrawer(
},
onSettingsCheck = {
showSettingsDialog = true
},
onAboutCheck = {
showAboutDialog = true
}
)
}, content = {
@ -262,6 +266,9 @@ fun MainScreenWithDrawer(
isAndroid
)
}
if (showAboutDialog) {
AboutDialog(onDismiss = { showAboutDialog = false })
}
val favoritePaths by sharedScreenModel.playlistItems.collectAsState()
val keyboardController = LocalSoftwareKeyboardController.current

View file

@ -76,11 +76,9 @@ fun Settings(
val player = sharedScreenModel.mediaPlayer
var expandedAudio by remember { mutableStateOf(player?.getCurrentPosition() != 0L) }
var expandedGeneral by remember { mutableStateOf(true) }
var expandedPrint by remember { mutableStateOf(false) }
fun openExclusive(target: String) {
expandedGeneral = (target == "General")
expandedPrint = (target == "Print")
expandedAudio = (target == "Audio")
}
@ -146,7 +144,11 @@ fun Settings(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text("Mode Plein Écran")
Text(
text = "Mode Plein Écran",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
Switch(
checked = isFullScreenEnabled,
onCheckedChange = { isChecked ->
@ -165,7 +167,7 @@ fun Settings(
) {
Text(
text = "Thème Sombre",
style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
@ -205,7 +207,7 @@ fun Settings(
) {
Text(
text = "Taille de la police",
style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
@ -341,27 +343,6 @@ fun Settings(
}
}
SettingsAccordion(
title = "Paramètres Impression",
isExpanded = expandedPrint,
onToggle = {
openExclusive("Print")
}
) {
Column(
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
}
}
}
SettingsAccordion(
title = "Paramètres Audio & Nuances",
isExpanded = expandedAudio,
@ -402,8 +383,9 @@ fun Settings(
}
)
Text(
if (isDynamicEnabled) "Désactiver" else "Activer",
fontSize = 15.sp
text = if (isDynamicEnabled) "Désactiver" else "Activer",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
}
@ -696,7 +678,7 @@ fun Settings(
)
Text(
text = "Règlage du player",
text = "Règlage du lecteur",
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onSurface,
@ -727,9 +709,10 @@ fun Settings(
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
if(!isAndroid) {
val countInStat = if (hasCountIn) "Désactiver" else "Activer"
Text(
if (hasCountIn) "Désactiver" else "Activer",
fontSize = 15.sp
text = countInStat,
style = MaterialTheme.typography.bodyMedium
)
}
Switch(

View file

@ -3,15 +3,12 @@ package mg.dot.feufaro.ui
import SharedScreenModel
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ListAlt
@ -22,10 +19,8 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.scale
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
@ -52,7 +47,8 @@ fun SimpleDrawerContent(
scope: CoroutineScope,
onScannerButtonClick: () -> Unit,
onSongSelected: (String) -> Unit,
onSettingsCheck: () -> Unit
onSettingsCheck: () -> Unit,
onAboutCheck: () -> Unit,
) {
var searchTxt by remember { mutableStateOf("") }
@ -72,7 +68,6 @@ fun SimpleDrawerContent(
val editMode by sharedScreenModel.modeEditor.collectAsState()
val chordView by sharedScreenModel.harmonyView.collectAsState()
var state2 by remember { mutableStateOf(false) }
ModalDrawerSheet(
modifier = Modifier.width(300.dp)
) {
@ -371,6 +366,7 @@ fun SimpleDrawerContent(
state = rememberTooltipState()
) {
IconButton(onClick = {
onAboutCheck()
scope.launch { drawerState.close() }
}) {
Icon(Icons.Default.Info, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary)

View file

@ -0,0 +1,10 @@
package mg.dot.feufaro.di
import androidx.compose.runtime.Composable
@Composable
actual fun rememberAppVersion(): String {
return System.getProperty("jpackage.app-version")
?: System.getProperty("app.version")
?: "0.0.0"
}