新批次的夜间模式适配代码

This commit is contained in:
2026-07-30 23:38:34 +08:00
parent b6d623a1eb
commit 42a30a73f9
11 changed files with 151 additions and 83 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ plugins {
android {
namespace = "com.lxh.battery_health"
compileSdk = 34
compileSdk = 36
ndkVersion = flutter.ndkVersion
compileOptions {
@@ -12,6 +12,7 @@ import android.os.Bundle
import android.provider.DocumentsContract
import android.provider.OpenableColumns
import android.view.Window // 🟢 必须包含
import android.app.Activity
import androidx.activity.ComponentActivity
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
@@ -135,7 +136,7 @@ class MainActivity : FlutterActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == FOLDER_PICKER_REQUEST && resultCode == ComponentActivity.RESULT_OK) {
if (requestCode == FOLDER_PICKER_REQUEST && resultCode == Activity.RESULT_OK) {
val uri = data?.data
if (uri != null) {
try {
+10 -19
View File
@@ -1,33 +1,24 @@
allprojects {
repositories {
maven {
url = uri("https://maven.aliyun.com/repository/public")
}
maven {
url = uri("https://maven.aliyun.com/repository/google")
}
maven {
url = uri("https://maven.aliyun.com/repository/gradle-plugin")
}
google()
mavenCentral()
}
// 根项目构建脚本
plugins {
id("com.android.application") version "8.13.0" apply false
id("org.jetbrains.kotlin.android") version "2.2.21" apply false
}
val newBuildDir: Directory =
rootProject.layout.buildDirectory
.dir("../../build")
.get()
// 统一重定向构建输出目录
val newBuildDir: Directory = rootProject.layout.buildDirectory
.dir("../../build")
.get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}
}
+4 -4
View File
@@ -1,7 +1,7 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
org.gradle.daemon=true
org.gradle.parallel=true
# This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false
android.builtInKotlin=true
# This newDsl flag was added automatically by Flutter migrator
android.newDsl=false
android.newDsl=true
+2 -2
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.14-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.12-all.zip
zipStorePath=wrapper/dists
+31 -13
View File
@@ -1,26 +1,44 @@
pluginManagement {
val flutterSdkPath =
run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val sdkPath = properties.getProperty("flutter.sdk")
require(sdkPath != null) { "flutter.sdk not set in local.properties" }
sdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
// 🟢 阿里云 gradle-plugin 镜像(专用)
maven {
url = uri("https://maven.aliyun.com/repository/gradle-plugin")
}
// 🟢 阿里云 public 聚合仓库(兜底)
maven {
url = uri("https://maven.aliyun.com/repository/public")
}
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.9.1" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
// 🟢 阿里云镜像放在最前面
maven { url = uri("https://maven.aliyun.com/repository/public") }
google()
mavenCentral()
}
}
include(":app")
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.13.0" apply false
id("org.jetbrains.kotlin.android") version "2.2.21" apply false
}
rootProject.name = "android"
include(":app")
+43 -4
View File
@@ -1,16 +1,49 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'pages/battery_health_page.dart';
import 'services/saf_storage_service.dart';
// 🆕 1.7.0 全局 Key,用于从子页面切换主题
final GlobalKey<_MyAppState> appKey = GlobalKey<_MyAppState>();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SafStorageService().init();
runApp(const MyApp());
final prefs = await SharedPreferences.getInstance();
final themeModeIndex = prefs.getInt('themeMode') ?? 0;
final themeMode =
ThemeMode.values[themeModeIndex.clamp(0, ThemeMode.values.length - 1)];
runApp(MyApp(key: appKey, initialThemeMode: themeMode));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
class MyApp extends StatefulWidget {
final ThemeMode initialThemeMode;
const MyApp({super.key, required this.initialThemeMode});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late ThemeMode _themeMode;
@override
void initState() {
super.initState();
_themeMode = widget.initialThemeMode;
}
void switchTheme(ThemeMode mode) {
setState(() {
_themeMode = mode;
});
SharedPreferences.getInstance().then((prefs) {
prefs.setInt('themeMode', mode.index);
});
}
@override
Widget build(BuildContext context) {
@@ -18,7 +51,7 @@ class MyApp extends StatelessWidget {
title: '电池健康度',
theme: _lightTheme(),
darkTheme: _darkTheme(),
themeMode: ThemeMode.system, // 默认跟随系统
themeMode: _themeMode,
home: const BatteryHealthPage(),
debugShowCheckedModeBanner: false,
);
@@ -41,6 +74,9 @@ class MyApp extends StatelessWidget {
colorScheme: const ColorScheme.light(
primary: Color(0xFF1A73E8),
secondary: Color(0xFF1A73E8),
surface: Colors.white,
onSurface: Colors.black, // 🟢 主要文字色
onSurfaceVariant: Colors.black87,
),
textTheme: const TextTheme(
bodyLarge: TextStyle(color: Colors.black),
@@ -68,6 +104,9 @@ class MyApp extends StatelessWidget {
colorScheme: const ColorScheme.dark(
primary: Color(0xFF4FC3F7),
secondary: Color(0xFF4FC3F7),
surface: Color(0xFF121212),
onSurface: Colors.white, // 🟢 主要文字色(夜间模式为白色)
onSurfaceVariant: Colors.white70,
),
textTheme: const TextTheme(
bodyLarge: TextStyle(color: Colors.white),
-1
View File
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
class AboutPage extends StatelessWidget {
+13 -1
View File
@@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:device_info_plus/device_info_plus.dart';
// --- 本地导入 ---
import '../main.dart';
import '../models/device_matching.dart';
import '../models/saf_permission_state.dart';
import '../models/data_abnormal_type.dart';
@@ -742,7 +743,18 @@ class _BatteryHealthPageState extends State<BatteryHealthPage> {
);
break;
case 'dark_mode':
// 夜间模式切换逻辑(需要全局状态管理)
// 循环切换:浅色 → 深色 → 跟随系统 → 浅色
final brightness = Theme.of(context).brightness;
ThemeMode next;
if (brightness == Brightness.light) {
next = ThemeMode.dark;
} else if (brightness == Brightness.dark) {
next = ThemeMode.system;
} else {
next = ThemeMode.light;
}
// 🆕 通过全局 key 调用 MyApp 的 switchTheme 方法
appKey.currentState?.switchTheme(next);
break;
}
},
+32 -19
View File
@@ -24,9 +24,12 @@ class BatteryInfoPanel extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final bool isVoltageAbnormal =
abnormalType == DataAbnormalType.voltageAbnormal;
final Color voltColor = isVoltageAbnormal ? Colors.red : Colors.black;
final Color defaultTextColor = Theme.of(context).colorScheme.onSurface;
final Color voltColor = isVoltageAbnormal ? Colors.red : defaultTextColor;
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -36,7 +39,8 @@ class BatteryInfoPanel extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoItem(
_buildIcon('voltage'),
context, // 🆕
_buildIcon('voltage', isDark),
'电压',
'${batteryVolt.toStringAsFixed(3)}V',
textColor: voltColor,
@@ -50,12 +54,14 @@ class BatteryInfoPanel extends StatelessWidget {
fontFamily: 'Flyme',
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.red,
color: isVoltageAbnormal
? Colors.red
: defaultTextColor,
),
children: [
const TextSpan(
TextSpan(
text: '',
style: TextStyle(
style: const TextStyle(
fontFamily: 'HarmonyOS_Sans_SC',
color: Colors.red,
),
@@ -76,12 +82,14 @@ class BatteryInfoPanel extends StatelessWidget {
fontFamily: 'Flyme',
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.blue,
color: isVoltageAbnormal
? Colors.red
: defaultTextColor,
),
children: [
const TextSpan(
TextSpan(
text: '',
style: TextStyle(
style: const TextStyle(
fontFamily: 'HarmonyOS_Sans_SC',
color: Colors.blue,
),
@@ -105,20 +113,22 @@ class BatteryInfoPanel extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoItem(
_buildIcon('temperature'),
context, // 🆕
_buildIcon('temperature', isDark),
'温度',
'${batteryTemp.toStringAsFixed(0)}',
textColor: defaultTextColor,
),
const SizedBox(height: 8),
Row(
children: [
RichText(
text: TextSpan(
style: const TextStyle(
style: TextStyle(
fontFamily: 'Flyme',
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.red,
color: defaultTextColor,
),
children: [
const TextSpan(
@@ -135,11 +145,11 @@ class BatteryInfoPanel extends StatelessWidget {
const SizedBox(width: 12),
RichText(
text: TextSpan(
style: const TextStyle(
style: TextStyle(
fontFamily: 'Flyme',
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.blue,
color: defaultTextColor,
),
children: [
const TextSpan(
@@ -162,43 +172,46 @@ class BatteryInfoPanel extends StatelessWidget {
);
}
Widget _buildIcon(String type) {
Widget _buildIcon(String type, bool isDark) {
final color = isDark ? Colors.white54 : Colors.grey;
switch (type) {
case 'voltage':
return SvgPicture.asset(
'assets/icons/si--lightning-fill.svg',
width: 18,
height: 18,
colorFilter: const ColorFilter.mode(Colors.grey, BlendMode.srcIn),
colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
);
case 'temperature':
return SvgPicture.asset(
'assets/icons/mdi--temperature.svg',
width: 18,
height: 18,
colorFilter: const ColorFilter.mode(Colors.grey, BlendMode.srcIn),
colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
);
default:
return const Icon(Icons.help_outline, size: 18, color: Colors.grey);
return Icon(Icons.help_outline, size: 18, color: color);
}
}
Widget _buildInfoItem(
BuildContext context, // 🆕
Widget icon,
String label,
String value, {
Color textColor = Colors.black,
}) {
final labelColor = Theme.of(context).colorScheme.onSurface.withOpacity(0.7);
return Row(
children: [
icon,
const SizedBox(width: 6),
Text(
label,
style: const TextStyle(
style: TextStyle(
fontFamily: 'HarmonyOS_Sans_SC',
fontSize: 14,
color: Colors.grey,
color: labelColor,
),
),
const SizedBox(width: 6),
+13 -18
View File
@@ -19,20 +19,20 @@ class BatterySummary extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final bool isAbnormal = abnormalType != DataAbnormalType.none;
final bool isCapacityAbnormal =
abnormalType == DataAbnormalType.capacityTooLow ||
abnormalType == DataAbnormalType.capacityTooHigh;
// 健康度颜色:异常时红色,否则按阈值
final Color healthColor = isAbnormal
? Colors.red
: (healthPercent < 70 ? Colors.red : Colors.black);
// 容量颜色:异常时红色,否则灰色
// 🟢 颜色完全动态
final Color defaultTextColor = Theme.of(context).colorScheme.onSurface;
final Color mutedTextColor = isDark
? Colors.grey.shade400
: const Color(0xFF5F5F5F);
final Color capacityColor = isCapacityAbnormal
? Colors.red
: const Color(0xFF5F5F5F);
: mutedTextColor;
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
@@ -49,7 +49,7 @@ class BatterySummary extends StatelessWidget {
fontSize: 40,
fontWeight: FontWeight.w500,
height: 1.0,
color: healthColor,
color: isAbnormal ? Colors.red : defaultTextColor,
),
),
const SizedBox(width: 2),
@@ -60,9 +60,7 @@ class BatterySummary extends StatelessWidget {
fontSize: 20,
fontWeight: FontWeight.w300,
height: 1.0,
color: healthColor == Colors.red
? Colors.red
: Colors.grey.shade600,
color: isAbnormal ? Colors.red : Colors.grey.shade600,
),
),
],
@@ -74,21 +72,18 @@ class BatterySummary extends StatelessWidget {
children: [
RichText(
text: TextSpan(
style: const TextStyle(
style: TextStyle(
fontFamily: 'Flyme',
fontSize: 16,
fontWeight: FontWeight.w500,
height: 1.2,
color: Colors.black,
color: defaultTextColor,
),
children: [
TextSpan(text: '$cycleCount'),
const TextSpan(
TextSpan(
text: ' cycles',
style: TextStyle(
fontFamily: 'HarmonyOS_Sans_SC',
color: Colors.black,
),
style: const TextStyle(fontFamily: 'HarmonyOS_Sans_SC'),
),
],
),