refactor: 积分榜导入导出改为右上角三点菜单,支持文件导出导入
This commit is contained in:
parent
da9828f4b2
commit
093a759ad4
@ -3,7 +3,10 @@ package com.unogame.ui.screens
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
@ -43,8 +46,49 @@ fun ScoreboardScreen(onBack: () -> Unit) {
|
|||||||
var detailEntry by remember { mutableStateOf<ScoreEntry?>(null) }
|
var detailEntry by remember { mutableStateOf<ScoreEntry?>(null) }
|
||||||
var showImportDialog by remember { mutableStateOf(false) }
|
var showImportDialog by remember { mutableStateOf(false) }
|
||||||
var importJson by remember { mutableStateOf("") }
|
var importJson by remember { mutableStateOf("") }
|
||||||
|
var showMenu by remember { mutableStateOf(false) }
|
||||||
val gson = remember { Gson() }
|
val gson = remember { Gson() }
|
||||||
|
|
||||||
|
// Export file launcher
|
||||||
|
val exportLauncher = rememberLauncherForActivityResult(
|
||||||
|
ActivityResultContracts.CreateDocument("application/json")
|
||||||
|
) { uri: Uri? ->
|
||||||
|
uri?.let {
|
||||||
|
try {
|
||||||
|
val json = gson.toJson(scores)
|
||||||
|
context.contentResolver.openOutputStream(it)?.use { out ->
|
||||||
|
out.write(json.toByteArray())
|
||||||
|
}
|
||||||
|
Toast.makeText(context, "备份已导出", Toast.LENGTH_SHORT).show()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "导出失败: ${e.message}", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import file launcher
|
||||||
|
val importLauncher = rememberLauncherForActivityResult(
|
||||||
|
ActivityResultContracts.OpenDocument()
|
||||||
|
) { uri: Uri? ->
|
||||||
|
uri?.let {
|
||||||
|
try {
|
||||||
|
val json = context.contentResolver.openInputStream(it)?.bufferedReader()?.readText() ?: ""
|
||||||
|
val imported = gson.fromJson(json, Array<ScoreEntry>::class.java)?.toList() ?: emptyList()
|
||||||
|
if (imported.isNotEmpty()) {
|
||||||
|
val merged = (scores + imported).distinctBy { e -> "${e.name}_${e.mode}_${e.date}" }
|
||||||
|
.sortedByDescending { e -> e.points }.take(50)
|
||||||
|
Scoreboard.saveScores(context, merged)
|
||||||
|
scores = merged
|
||||||
|
Toast.makeText(context, "成功导入 ${imported.size} 条记录", Toast.LENGTH_SHORT).show()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "文件中无有效数据", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "导入失败: ${e.message}", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val filtered = if (selectedFilter == "全部") scores
|
val filtered = if (selectedFilter == "全部") scores
|
||||||
else scores.filter { it.mode == selectedFilter }
|
else scores.filter { it.mode == selectedFilter }
|
||||||
|
|
||||||
@ -57,42 +101,55 @@ fun ScoreboardScreen(onBack: () -> Unit) {
|
|||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.Default.ArrowBack, "返回", tint = Color.White)
|
Icon(Icons.Default.ArrowBack, "返回", tint = Color.White)
|
||||||
}
|
}
|
||||||
Text("积分排行榜", fontSize = 24.sp, fontWeight = FontWeight.Bold, color = Color.White)
|
Text("积分排行榜", fontSize = 24.sp, fontWeight = FontWeight.Bold, color = Color.White, modifier = Modifier.weight(1f))
|
||||||
|
Box {
|
||||||
|
IconButton(onClick = { showMenu = true }) {
|
||||||
|
Icon(Icons.Default.MoreVert, "菜单", tint = Color.White)
|
||||||
}
|
}
|
||||||
|
DropdownMenu(
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
expanded = showMenu,
|
||||||
|
onDismissRequest = { showMenu = false }
|
||||||
// Import / Export buttons
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
DropdownMenuItem(
|
||||||
|
text = { Text("导出到文件") },
|
||||||
onClick = {
|
onClick = {
|
||||||
|
showMenu = false
|
||||||
|
exportLauncher.launch("uno_scoreboard_backup.json")
|
||||||
|
},
|
||||||
|
leadingIcon = { Icon(Icons.Default.FileUpload, null) }
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text("从文件导入") },
|
||||||
|
onClick = {
|
||||||
|
showMenu = false
|
||||||
|
importLauncher.launch(arrayOf("application/json", "*/*"))
|
||||||
|
},
|
||||||
|
leadingIcon = { Icon(Icons.Default.FileDownload, null) }
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text("复制备份") },
|
||||||
|
onClick = {
|
||||||
|
showMenu = false
|
||||||
val json = gson.toJson(scores)
|
val json = gson.toJson(scores)
|
||||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
clipboard.setPrimaryClip(ClipData.newPlainText("uno_scoreboard", json))
|
clipboard.setPrimaryClip(ClipData.newPlainText("uno_scoreboard", json))
|
||||||
Toast.makeText(context, "已复制备份JSON到剪贴板", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "已复制JSON到剪贴板", Toast.LENGTH_SHORT).show()
|
||||||
},
|
},
|
||||||
modifier = Modifier.weight(1f),
|
leadingIcon = { Icon(Icons.Default.ContentCopy, null) }
|
||||||
colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.White.copy(alpha = 0.7f))
|
)
|
||||||
) {
|
DropdownMenuItem(
|
||||||
Icon(Icons.Default.FileUpload, null, modifier = Modifier.size(16.dp))
|
text = { Text("粘贴导入") },
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
onClick = {
|
||||||
Text("导出备份", fontSize = 12.sp)
|
showMenu = false
|
||||||
|
showImportDialog = true
|
||||||
|
},
|
||||||
|
leadingIcon = { Icon(Icons.Default.ContentPaste, null) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
OutlinedButton(
|
|
||||||
onClick = { showImportDialog = true },
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.White.copy(alpha = 0.7f))
|
|
||||||
) {
|
|
||||||
Icon(Icons.Default.FileDownload, null, modifier = Modifier.size(16.dp))
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
Text("导入备份", fontSize = 12.sp)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
// Mode filter chips
|
// Mode filter chips
|
||||||
if (scores.isNotEmpty()) {
|
if (scores.isNotEmpty()) {
|
||||||
@ -282,7 +339,7 @@ fun ScoreboardScreen(onBack: () -> Unit) {
|
|||||||
if (showImportDialog) {
|
if (showImportDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { showImportDialog = false },
|
onDismissRequest = { showImportDialog = false },
|
||||||
title = { Text("导入备份", color = GoldAccent) },
|
title = { Text("粘贴导入", color = GoldAccent) },
|
||||||
text = {
|
text = {
|
||||||
Column {
|
Column {
|
||||||
Text("粘贴之前导出的JSON数据:", color = Color.White.copy(alpha = 0.7f), fontSize = 14.sp)
|
Text("粘贴之前导出的JSON数据:", color = Color.White.copy(alpha = 0.7f), fontSize = 14.sp)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user