From 093a759ad4021564de652aa225a522eb13b8a6df Mon Sep 17 00:00:00 2001 From: flykhan Date: Sun, 26 Apr 2026 17:54:09 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=AF=E5=88=86=E6=A6=9C?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E6=94=B9=E4=B8=BA=E5=8F=B3?= =?UTF-8?q?=E4=B8=8A=E8=A7=92=E4=B8=89=E7=82=B9=E8=8F=9C=E5=8D=95=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=96=87=E4=BB=B6=E5=AF=BC=E5=87=BA=E5=AF=BC?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unogame/ui/screens/ScoreboardScreen.kt | 125 +++++++++++++----- 1 file changed, 91 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/unogame/ui/screens/ScoreboardScreen.kt b/app/src/main/java/com/unogame/ui/screens/ScoreboardScreen.kt index 0697ca3..33adb64 100644 --- a/app/src/main/java/com/unogame/ui/screens/ScoreboardScreen.kt +++ b/app/src/main/java/com/unogame/ui/screens/ScoreboardScreen.kt @@ -3,7 +3,10 @@ package com.unogame.ui.screens import android.content.ClipData import android.content.ClipboardManager import android.content.Context +import android.net.Uri import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll @@ -43,8 +46,49 @@ fun ScoreboardScreen(onBack: () -> Unit) { var detailEntry by remember { mutableStateOf(null) } var showImportDialog by remember { mutableStateOf(false) } var importJson by remember { mutableStateOf("") } + var showMenu by remember { mutableStateOf(false) } 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::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 else scores.filter { it.mode == selectedFilter } @@ -57,43 +101,56 @@ fun ScoreboardScreen(onBack: () -> Unit) { IconButton(onClick = onBack) { 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( + expanded = showMenu, + onDismissRequest = { showMenu = false } + ) { + DropdownMenuItem( + text = { Text("导出到文件") }, + 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 clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboard.setPrimaryClip(ClipData.newPlainText("uno_scoreboard", json)) + Toast.makeText(context, "已复制JSON到剪贴板", Toast.LENGTH_SHORT).show() + }, + leadingIcon = { Icon(Icons.Default.ContentCopy, null) } + ) + DropdownMenuItem( + text = { Text("粘贴导入") }, + onClick = { + showMenu = false + showImportDialog = true + }, + leadingIcon = { Icon(Icons.Default.ContentPaste, null) } + ) + } + } } Spacer(modifier = Modifier.height(16.dp)) - // Import / Export buttons - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - OutlinedButton( - onClick = { - val json = gson.toJson(scores) - val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - clipboard.setPrimaryClip(ClipData.newPlainText("uno_scoreboard", json)) - Toast.makeText(context, "已复制备份JSON到剪贴板", Toast.LENGTH_SHORT).show() - }, - modifier = Modifier.weight(1f), - colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.White.copy(alpha = 0.7f)) - ) { - Icon(Icons.Default.FileUpload, null, modifier = Modifier.size(16.dp)) - Spacer(modifier = Modifier.width(4.dp)) - Text("导出备份", fontSize = 12.sp) - } - 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)) - // Mode filter chips if (scores.isNotEmpty()) { Row( @@ -282,7 +339,7 @@ fun ScoreboardScreen(onBack: () -> Unit) { if (showImportDialog) { AlertDialog( onDismissRequest = { showImportDialog = false }, - title = { Text("导入备份", color = GoldAccent) }, + title = { Text("粘贴导入", color = GoldAccent) }, text = { Column { Text("粘贴之前导出的JSON数据:", color = Color.White.copy(alpha = 0.7f), fontSize = 14.sp)