From 18dc46edcacb6ed89efebbc7e66b8fffaf6892b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Jul 2026 23:04:36 +0800 Subject: [PATCH] Add github token settings for updater --- .../sfa/vendor/GitHubUpdateChecker.kt | 10 +- .../io/nekohasekai/sfa/vendor/UpdateWorker.kt | 2 +- .../screen/settings/AppSettingsScreen.kt | 102 ++++++++++++++++++ .../nekohasekai/sfa/constant/SettingsKey.kt | 1 + .../io/nekohasekai/sfa/database/Settings.kt | 1 + app/src/main/res/values-fa/strings.xml | 2 + app/src/main/res/values-ru-rRU/strings.xml | 2 + app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + .../java/io/nekohasekai/sfa/vendor/Vendor.kt | 2 +- .../java/io/nekohasekai/sfa/vendor/Vendor.kt | 2 +- 12 files changed, 124 insertions(+), 6 deletions(-) diff --git a/app/src/github/java/io/nekohasekai/sfa/vendor/GitHubUpdateChecker.kt b/app/src/github/java/io/nekohasekai/sfa/vendor/GitHubUpdateChecker.kt index 15f8ba7..ab0c1c2 100644 --- a/app/src/github/java/io/nekohasekai/sfa/vendor/GitHubUpdateChecker.kt +++ b/app/src/github/java/io/nekohasekai/sfa/vendor/GitHubUpdateChecker.kt @@ -25,8 +25,8 @@ class GitHubUpdateChecker : Closeable { private val json = Json { ignoreUnknownKeys = true } - fun checkUpdate(track: UpdateTrack): UpdateInfo? { - val releases = getReleases() + fun checkUpdate(track: UpdateTrack, githubToken: String): UpdateInfo? { + val releases = getReleases(githubToken) var selected: ReleaseCandidate? = null for (release in releases) { @@ -64,10 +64,14 @@ class GitHubUpdateChecker : Closeable { ) } - private fun getReleases(): List { + private fun getReleases(githubToken: String): List { val request = client.newRequest() request.setURL(RELEASES_URL) request.setHeader("Accept", "application/vnd.github.v3+json") + val token = githubToken.trim() + if (token.isNotEmpty()) { + request.setHeader("Authorization", "Bearer $token") + } request.setUserAgent(HTTPClient.userAgent) val response = request.execute() diff --git a/app/src/github/java/io/nekohasekai/sfa/vendor/UpdateWorker.kt b/app/src/github/java/io/nekohasekai/sfa/vendor/UpdateWorker.kt index a4ee0af..059458d 100644 --- a/app/src/github/java/io/nekohasekai/sfa/vendor/UpdateWorker.kt +++ b/app/src/github/java/io/nekohasekai/sfa/vendor/UpdateWorker.kt @@ -65,7 +65,7 @@ class UpdateWorker(private val appContext: Context, params: WorkerParameters) : UpdateSource.FDROID -> checkFDroidUpdate(appContext) UpdateSource.GITHUB -> { val track = UpdateTrack.fromString(Settings.updateTrack) - GitHubUpdateChecker().use { it.checkUpdate(track) } + GitHubUpdateChecker().use { it.checkUpdate(track, Settings.githubToken) } } } diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/AppSettingsScreen.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/AppSettingsScreen.kt index 5fc0613..a4f0f73 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/AppSettingsScreen.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/AppSettingsScreen.kt @@ -27,17 +27,21 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Terminal +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.outlined.AdminPanelSettings import androidx.compose.material.icons.outlined.Autorenew import androidx.compose.material.icons.outlined.DeleteForever import androidx.compose.material.icons.outlined.DeleteSweep import androidx.compose.material.icons.outlined.Download import androidx.compose.material.icons.outlined.Info +import androidx.compose.material.icons.outlined.Key import androidx.compose.material.icons.outlined.Language import androidx.compose.material.icons.outlined.NewReleases import androidx.compose.material.icons.outlined.Notifications @@ -59,6 +63,7 @@ import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.RadioButton import androidx.compose.material3.Switch import androidx.compose.material3.Text @@ -79,6 +84,9 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp import androidx.core.app.NotificationManagerCompat import androidx.core.os.LocaleListCompat @@ -141,6 +149,8 @@ fun AppSettingsScreen( var currentSource by remember { mutableStateOf(Settings.updateSource) } var showTrackDialog by remember { mutableStateOf(false) } var currentTrack by remember { mutableStateOf(Settings.updateTrack) } + var showGitHubTokenDialog by remember { mutableStateOf(false) } + var githubToken by remember { mutableStateOf(Settings.githubToken) } var checkUpdateEnabled by remember { mutableStateOf(Settings.checkUpdateEnabled) } var showErrorDialog by remember { mutableStateOf(null) } @@ -255,6 +265,20 @@ fun AppSettingsScreen( ) } + if (showGitHubTokenDialog) { + GitHubTokenDialog( + currentToken = githubToken, + onSave = { token -> + githubToken = token + scope.launch(Dispatchers.IO) { + Settings.githubToken = token + } + showGitHubTokenDialog = false + }, + onDismiss = { showGitHubTokenDialog = false }, + ) + } + showErrorDialog?.let { message -> AlertDialog( onDismissRequest = { showErrorDialog = null }, @@ -781,6 +805,9 @@ fun AppSettingsScreen( if (Vendor.hasCustomUpdate) { count += 1 } + if (Vendor.hasCustomUpdate && !isFDroid) { + count += 1 + } if (isFDroid) { count += 1 } @@ -884,6 +911,38 @@ fun AppSettingsScreen( ) } + if (Vendor.hasCustomUpdate && !isFDroid) { + ListItem( + headlineContent = { + Text( + stringResource(R.string.github_token), + style = MaterialTheme.typography.bodyLarge, + ) + }, + supportingContent = { + Text( + stringResource(R.string.github_token_description), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + }, + leadingContent = { + Icon( + imageVector = Icons.Outlined.Key, + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + ) + }, + modifier = + updateItemModifier() + .clickable { showGitHubTokenDialog = true }, + colors = + ListItemDefaults.colors( + containerColor = Color.Transparent, + ), + ) + } + if (isFDroid) { ListItem( headlineContent = { @@ -1408,6 +1467,49 @@ private fun UpdateTrackDialog( ) } +@Composable +private fun GitHubTokenDialog( + currentToken: String, + onSave: (String) -> Unit, + onDismiss: () -> Unit, +) { + var token by remember(currentToken) { mutableStateOf(currentToken) } + var tokenVisible by remember { mutableStateOf(false) } + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(stringResource(R.string.github_token)) }, + text = { + OutlinedTextField( + value = token, + onValueChange = { token = it }, + modifier = Modifier.fillMaxWidth(), + singleLine = true, + visualTransformation = if (tokenVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { tokenVisible = !tokenVisible }) { + Icon( + imageVector = if (tokenVisible) Icons.Default.VisibilityOff else Icons.Default.Visibility, + contentDescription = null, + ) + } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + ) + }, + confirmButton = { + TextButton(onClick = { onSave(token.trim()) }) { + Text(stringResource(R.string.save)) + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text(stringResource(R.string.cancel)) + } + }, + ) +} + @Composable private fun LanguageDialog( currentTag: String, diff --git a/app/src/main/java/io/nekohasekai/sfa/constant/SettingsKey.kt b/app/src/main/java/io/nekohasekai/sfa/constant/SettingsKey.kt index 81caf34..a775387 100644 --- a/app/src/main/java/io/nekohasekai/sfa/constant/SettingsKey.kt +++ b/app/src/main/java/io/nekohasekai/sfa/constant/SettingsKey.kt @@ -7,6 +7,7 @@ object SettingsKey { const val UPDATE_CHECK_PROMPTED = "update_check_prompted" const val UPDATE_SOURCE = "update_source" const val UPDATE_TRACK = "update_track" + const val GITHUB_TOKEN = "github_token" const val FDROID_MIRROR_URL = "fdroid_mirror_url" const val FDROID_CUSTOM_MIRRORS = "fdroid_custom_mirrors" const val SILENT_INSTALL_ENABLED = "silent_install_enabled" diff --git a/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt b/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt index f4ee6d0..90bd43b 100644 --- a/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt +++ b/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt @@ -56,6 +56,7 @@ object Settings { "stable" } } + var githubToken by dataStore.string(SettingsKey.GITHUB_TOKEN) { "" } var silentInstallEnabled by dataStore.boolean(SettingsKey.SILENT_INSTALL_ENABLED) { false } var silentInstallMethod by dataStore.string(SettingsKey.SILENT_INSTALL_METHOD) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 0faf96f..a2d6785 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -286,6 +286,8 @@ منبع به‌روزرسانی GitHub F-Droid + توکن GitHub + دریافت محدودیت نرخ بالاتر برای API گیت‌هاب آینه F-Droid انتخاب خودکار بر اساس تأخیر در حال تست… diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 50ffd08..4043a97 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -286,6 +286,8 @@ Источник обновлений GitHub F-Droid + Токен GitHub + Получите более высокие лимиты запросов GitHub API Зеркало F-Droid Автовыбор по задержке Тестирование… diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 8e4cc46..e7ee1ea 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -286,6 +286,8 @@ 更新来源 GitHub F-Droid + GitHub Token + 获取更高的 GitHub API 速率限制 F-Droid 镜像 根据延迟自动选择 测试中… diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 10357ea..959b000 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -286,6 +286,8 @@ 更新來源 GitHub F-Droid + GitHub Token + 取得更高的 GitHub API 速率限制 F-Droid 鏡像 依延遲自動選擇 測試中… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 75afc46..a64b284 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -275,6 +275,8 @@ Update Source GitHub F-Droid + GitHub Token + Get higher GitHub API rate limits Update Track Stable Beta diff --git a/app/src/other/java/io/nekohasekai/sfa/vendor/Vendor.kt b/app/src/other/java/io/nekohasekai/sfa/vendor/Vendor.kt index 32876c4..fa39ea9 100644 --- a/app/src/other/java/io/nekohasekai/sfa/vendor/Vendor.kt +++ b/app/src/other/java/io/nekohasekai/sfa/vendor/Vendor.kt @@ -104,7 +104,7 @@ object Vendor : VendorInterface { UpdateSource.GITHUB -> { val track = UpdateTrack.fromString(Settings.updateTrack) GitHubUpdateChecker().use { checker -> - checker.checkUpdate(track) + checker.checkUpdate(track, Settings.githubToken) } } } diff --git a/app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/Vendor.kt b/app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/Vendor.kt index 835264d..0cae2ea 100644 --- a/app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/Vendor.kt +++ b/app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/Vendor.kt @@ -98,7 +98,7 @@ object Vendor : VendorInterface { override fun checkUpdateAsync(): UpdateInfo? { val track = UpdateTrack.fromString(Settings.updateTrack) return GitHubUpdateChecker().use { checker -> - checker.checkUpdate(track) + checker.checkUpdate(track, Settings.githubToken) } }