diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8a4eeb0..6988520 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "com.a2i.forwarder" minSdk = 34 targetSdk = 36 - versionCode = 21 - versionName = "1.8.4" + versionCode = 22 + versionName = "1.8.5" } signingConfigs { diff --git a/app/src/main/java/com/a2i/forwarder/core/EmailSender.kt b/app/src/main/java/com/a2i/forwarder/core/EmailSender.kt index 4a85ef2..33e044f 100644 --- a/app/src/main/java/com/a2i/forwarder/core/EmailSender.kt +++ b/app/src/main/java/com/a2i/forwarder/core/EmailSender.kt @@ -120,7 +120,6 @@ object EmailSender { /** 如果电邮转发已启用且收件人非空,异步发邮件(fire-and-forget,不阻塞主流程)。 */ fun trySend(app: A2iApp, title: String, body: String, scope: CoroutineScope) { val s = app.settings - if (!s.emailForwardingEnabled.value) return val configs = s.emailServers.value.filter { it.enabled && it.to.isNotBlank() && it.host.isNotBlank() } if (configs.isEmpty()) return scope.launch { diff --git a/app/src/main/java/com/a2i/forwarder/core/SmsFallbackForwarder.kt b/app/src/main/java/com/a2i/forwarder/core/SmsFallbackForwarder.kt index b7d15e2..dbcdd9e 100644 --- a/app/src/main/java/com/a2i/forwarder/core/SmsFallbackForwarder.kt +++ b/app/src/main/java/com/a2i/forwarder/core/SmsFallbackForwarder.kt @@ -35,7 +35,6 @@ class SmsFallbackForwarder(private val context: Context) { /** 尝试用短信转发(遍历所有启用的目标号,按 stopOnFirst 决定发通一条止还是全发)。 */ fun forward(d: Decision) { scope.launch { - if (!settings.smsFallbackEnabled.value) return@launch if (settings.smsSuspended.value) { log(d, "failed", "短信已挂起(余额不足)") return@launch diff --git a/app/src/main/java/com/a2i/forwarder/ui/screens/SettingsScreen.kt b/app/src/main/java/com/a2i/forwarder/ui/screens/SettingsScreen.kt index 8814c2a..b8f07ec 100644 --- a/app/src/main/java/com/a2i/forwarder/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/com/a2i/forwarder/ui/screens/SettingsScreen.kt @@ -226,68 +226,78 @@ fun SettingsScreen(onOpenLog: () -> Unit) { // ===== 电邮 ===== item { - SectionCard("电邮转发", subtitle = "SMTPS 直发邮件") { - SwitchRow(title = "启用电邮转发", subtitle = if (emailEnabled) "已开启" else "已关闭", checked = emailEnabled) { v -> app.appScope.launch { app.settings.setEmailForwarding(v) } } - if (emailEnabled) { - SwitchRow(title = "发通一条就停", subtitle = if (emailStopFirst) "容错:首个成功止" else "广播:每个都发", checked = emailStopFirst) { v -> app.appScope.launch { app.settings.setEmailStopOnFirst(v) } } - if (emailServers.isNotEmpty()) { - Spacer(Modifier.size(8.dp)) - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - emailServers.forEachIndexed { i, s -> - ConfigRow( - title = s.name.ifBlank { s.to }, - subtitle = "${s.host}:${s.port} · ${s.user} → ${s.to}", - enabled = s.enabled, isFirst = i == 0, isLast = i == emailServers.lastIndex, - onToggle = { v -> app.appScope.launch { app.settings.setEmailEnabled(s.id, v) } }, - onEdit = { editingEmail = s }, onDelete = { app.appScope.launch { app.settings.deleteEmail(s.id) } }, - onMoveUp = { app.appScope.launch { app.settings.moveEmail(s.id, true) } }, - onMoveDown = { app.appScope.launch { app.settings.moveEmail(s.id, false) } }, - onTest = { app.appScope.launch { EmailSender.send(s.host, s.port, s.user, s.password, s.from, s.to, "a2i测试", "电邮配置测试") } }, - ) - } + SectionCard( + "电邮转发", + subtitle = "勾选的邮箱参与转发;开关切换容错/广播", + headerAction = { + CompactStopOnFirstSwitch( + checked = emailStopFirst, + onChange = { v -> app.appScope.launch { app.settings.setEmailStopOnFirst(v) } }, + ) + }, + ) { + if (emailServers.isNotEmpty()) { + Spacer(Modifier.size(8.dp)) + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + emailServers.forEachIndexed { i, s -> + ConfigRow( + title = s.name.ifBlank { s.to }, + subtitle = "${s.host}:${s.port} · ${s.user} → ${s.to}", + enabled = s.enabled, isFirst = i == 0, isLast = i == emailServers.lastIndex, + onToggle = { v -> app.appScope.launch { app.settings.setEmailEnabled(s.id, v) } }, + onEdit = { editingEmail = s }, onDelete = { app.appScope.launch { app.settings.deleteEmail(s.id) } }, + onMoveUp = { app.appScope.launch { app.settings.moveEmail(s.id, true) } }, + onMoveDown = { app.appScope.launch { app.settings.moveEmail(s.id, false) } }, + onTest = { app.appScope.launch { EmailSender.send(s.host, s.port, s.user, s.password, s.from, s.to, "a2i测试", "电邮配置测试") } }, + ) } } - AddButton { showAddEmail = true } } + AddButton { showAddEmail = true } } } // ===== 短信兜底 ===== item { - SectionCard("断网短信兜底", subtitle = "无网络时把验证码/来电用短信发出去") { - SwitchRow(title = "启用短信兜底", subtitle = if (smsFallback) "已开启" else "已关闭", checked = smsFallback) { v -> app.appScope.launch { app.settings.setSmsFallback(v) } } - if (smsFallback) { - SwitchRow(title = "发通一条就停", subtitle = if (smsStopFirst) "容错:首个成功止" else "广播:每个都发", checked = smsStopFirst) { v -> app.appScope.launch { app.settings.setSmsStopOnFirst(v) } } - if (!hasSmsPerm) { - Spacer(Modifier.size(4.dp)) - OutlinedButton(onClick = { smsPermLauncher.launch(android.Manifest.permission.SEND_SMS) }, modifier = Modifier.fillMaxWidth()) { Text("授予短信权限") } - } - if (smsTargets.isNotEmpty()) { - Spacer(Modifier.size(8.dp)) - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - smsTargets.forEachIndexed { i, s -> - ConfigRow( - title = s.name.ifBlank { s.number }, - subtitle = s.number, - enabled = s.enabled, isFirst = i == 0, isLast = i == smsTargets.lastIndex, - onToggle = { v -> app.appScope.launch { app.settings.setSmsTargetEnabled(s.id, v) } }, - onEdit = { editingSms = s }, onDelete = { app.appScope.launch { app.settings.deleteSmsTarget(s.id) } }, - onMoveUp = { app.appScope.launch { app.settings.moveSmsTarget(s.id, true) } }, - onMoveDown = { app.appScope.launch { app.settings.moveSmsTarget(s.id, false) } }, - onTest = null, - ) - } + SectionCard( + "断网短信兜底", + subtitle = "勾选的目标号参与转发;开关切换容错/广播", + headerAction = { + CompactStopOnFirstSwitch( + checked = smsStopFirst, + onChange = { v -> app.appScope.launch { app.settings.setSmsStopOnFirst(v) } }, + ) + }, + ) { + if (!hasSmsPerm) { + Spacer(Modifier.size(4.dp)) + OutlinedButton(onClick = { smsPermLauncher.launch(android.Manifest.permission.SEND_SMS) }, modifier = Modifier.fillMaxWidth()) { Text("授予短信权限") } + } + if (smsTargets.isNotEmpty()) { + Spacer(Modifier.size(8.dp)) + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + smsTargets.forEachIndexed { i, s -> + ConfigRow( + title = s.name.ifBlank { s.number }, + subtitle = s.number, + enabled = s.enabled, isFirst = i == 0, isLast = i == smsTargets.lastIndex, + onToggle = { v -> app.appScope.launch { app.settings.setSmsTargetEnabled(s.id, v) } }, + onEdit = { editingSms = s }, onDelete = { app.appScope.launch { app.settings.deleteSmsTarget(s.id) } }, + onMoveUp = { app.appScope.launch { app.settings.moveSmsTarget(s.id, true) } }, + onMoveDown = { app.appScope.launch { app.settings.moveSmsTarget(s.id, false) } }, + onTest = null, + ) } } - AddButton { showAddSms = true } - Spacer(Modifier.size(8.dp)) - val balanceText = when { - smsSuspended -> "已挂起(余额不足)" - smsBalance < 0 -> "余额未知" - else -> "剩余约 $smsBalance 条" - } - Text("运营商:${detectedCarrier.displayName} · 余额:$balanceText · 手动额度:$smsManualQuota", style = MaterialTheme.typography.bodySmall, color = if (smsSuspended) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant) } + AddButton { showAddSms = true } + Spacer(Modifier.size(8.dp)) + val balanceText = when { + smsSuspended -> "已挂起(余额不足)" + smsBalance < 0 -> "余额未知" + else -> "剩余约 $smsBalance 条" + } + Text("运营商:${detectedCarrier.displayName} · 余额:$balanceText · 手动额度:$smsManualQuota", style = MaterialTheme.typography.bodySmall, color = if (smsSuspended) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant) } }