Display developer names & links on AboutScreen
This commit is contained in:
parent
62b1f6784a
commit
0ff426b9ac
1 changed files with 240 additions and 60 deletions
|
|
@ -3,21 +3,31 @@ package mg.dot.feufaro.ui
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Code
|
import androidx.compose.material.icons.filled.Code
|
||||||
import androidx.compose.material.icons.filled.Email
|
import androidx.compose.material.icons.filled.Description
|
||||||
import androidx.compose.material.icons.filled.Language
|
import androidx.compose.material.icons.filled.Language
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.compose.ui.platform.UriHandler
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.TextUnit
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
|
|
@ -27,12 +37,82 @@ import feufaro.composeapp.generated.resources.icon
|
||||||
import mg.dot.feufaro.di.rememberAppVersion
|
import mg.dot.feufaro.di.rememberAppVersion
|
||||||
import mg.dot.feufaro.getPlatform
|
import mg.dot.feufaro.getPlatform
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
|
import java.awt.Desktop
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
private var lastClickTime = 0L
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutDialog(onDismiss: () -> Unit) {
|
fun AboutDialog(onDismiss: () -> Unit) {
|
||||||
val platform = getPlatform()
|
val platform = getPlatform()
|
||||||
val appVersion = rememberAppVersion()
|
val appVersion = rememberAppVersion()
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
val developers = listOf(
|
||||||
|
"RANDIMBISOA Mahefa" to "https://github.com/DotMG",
|
||||||
|
"RAKOTOARIMALALA Hasinjato M." to "https://github.com/Hasinjato",
|
||||||
|
"RAMANAHADRAY Tsinjo Anjaratahina" to "https://github.com/Tiji-Tahina"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun openWebUrl(url: String, uriHandler: UriHandler) {
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
if (currentTime - lastClickTime < 1000) return
|
||||||
|
lastClickTime = currentTime
|
||||||
|
|
||||||
|
val isAndroid = getPlatform().name.startsWith("Android")
|
||||||
|
|
||||||
|
if (isAndroid) {
|
||||||
|
try {
|
||||||
|
uriHandler.openUri(url)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("Erreur Android : ${e.message}")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux / Windows
|
||||||
|
Thread {
|
||||||
|
try {
|
||||||
|
val os = System.getProperty("os.name")?.lowercase() ?: ""
|
||||||
|
when {
|
||||||
|
os.contains("win") -> {
|
||||||
|
ProcessBuilder("cmd.exe", "/c", "start", url.replace("&", "^&")).start()
|
||||||
|
}
|
||||||
|
else -> { // Linux / Unix
|
||||||
|
val candidates = listOf(
|
||||||
|
arrayOf("gio", "open", url), // GNOME / GTK
|
||||||
|
arrayOf("kioclient6", "exec", url), // KDE Plasma 6
|
||||||
|
arrayOf("kioclient5", "exec", url), // KDE Plasma 5
|
||||||
|
arrayOf("x-www-browser", url), // Debian / Ubuntu
|
||||||
|
arrayOf("firefox", url),
|
||||||
|
arrayOf("google-chrome", url),
|
||||||
|
arrayOf("zen-browser", url)
|
||||||
|
)
|
||||||
|
|
||||||
|
var success = false
|
||||||
|
for (cmd in candidates) {
|
||||||
|
try {
|
||||||
|
val process = ProcessBuilder(*cmd).start()
|
||||||
|
if (process.isAlive || process.waitFor() == 0) {
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||||
|
Desktop.getDesktop().browse(URI(url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("Erreur ouverture URL : ${e.message}")
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
val devScrollState = rememberScrollState()
|
||||||
Dialog(
|
Dialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
properties = DialogProperties(
|
properties = DialogProperties(
|
||||||
|
|
@ -56,67 +136,123 @@ fun AboutDialog(onDismiss: () -> Unit) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(24.dp),
|
.padding(10.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.TopEnd) {
|
Column(
|
||||||
IconButton(
|
modifier = Modifier
|
||||||
onClick = onDismiss,
|
.fillMaxWidth()
|
||||||
modifier = Modifier.size(32.dp)
|
.weight(1f, fill = false)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
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
|
||||||
) {
|
) {
|
||||||
Icon(
|
Image(
|
||||||
imageVector = Icons.Default.Close,
|
painter = painterResource(Res.drawable.icon),
|
||||||
contentDescription = "Fermer",
|
contentDescription = "Logo Feufaro",
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
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 = 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(16.dp))
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp)
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f))
|
||||||
|
) {
|
||||||
|
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(devScrollState),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
developers.forEach { (name, gitUrl) ->
|
||||||
|
AssistChip(
|
||||||
|
onClick = { openWebUrl(gitUrl, uriHandler) },
|
||||||
|
label = {
|
||||||
|
AutoResizedText(
|
||||||
|
text = name,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
minFontSize = 9.sp
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Code,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Default.OpenInNew,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(14.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = 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))
|
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
|
@ -124,9 +260,21 @@ fun AboutDialog(onDismiss: () -> Unit) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceEvenly
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
) {
|
) {
|
||||||
InfoIconItem(icon = Icons.Default.Language, label = "Site Web", onClick = { })
|
InfoIconItem(
|
||||||
InfoIconItem(icon = Icons.Default.Email, label = "Contact", onClick = { })
|
icon = Icons.Default.Language,
|
||||||
InfoIconItem(icon = Icons.Default.Code, label = "Licence", onClick = { })
|
label = "Site Web",
|
||||||
|
onClick = { openWebUrl("https://feufar.ooo", uriHandler) }
|
||||||
|
)
|
||||||
|
InfoIconItem(
|
||||||
|
icon = Icons.Default.Code,
|
||||||
|
label = "Code Source",
|
||||||
|
onClick = { openWebUrl("https://code.homemade.mg/mahefa/feufaro", uriHandler) }
|
||||||
|
)
|
||||||
|
InfoIconItem(
|
||||||
|
icon = Icons.Default.Description,
|
||||||
|
label = "Licence",
|
||||||
|
onClick = { openWebUrl("https://www.gnu.org/licenses/gpl-3.0-standalone.html", uriHandler) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
@ -163,4 +311,36 @@ fun InfoIconItem(icon: ImageVector, label: String, onClick: () -> Unit) {
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@Composable
|
||||||
|
fun AutoResizedText(
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
style: TextStyle = LocalTextStyle.current,
|
||||||
|
color: Color = Color.Unspecified,
|
||||||
|
minFontSize: TextUnit = 9.sp
|
||||||
|
) {
|
||||||
|
var resizedTextStyle by remember(text) { mutableStateOf(style) }
|
||||||
|
var readyToDraw by remember(text) { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
color = color,
|
||||||
|
modifier = modifier.drawWithContent {
|
||||||
|
if (readyToDraw) drawContent()
|
||||||
|
},
|
||||||
|
style = resizedTextStyle,
|
||||||
|
maxLines = 1,
|
||||||
|
softWrap = false,
|
||||||
|
overflow = TextOverflow.Clip,
|
||||||
|
onTextLayout = { result ->
|
||||||
|
if (result.hasVisualOverflow && resizedTextStyle.fontSize > minFontSize) {
|
||||||
|
resizedTextStyle = resizedTextStyle.copy(
|
||||||
|
fontSize = (resizedTextStyle.fontSize.value - 1).sp
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
readyToDraw = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue