Color scheme

This commit is contained in:
LittleSheep 2024-12-22 13:07:22 +08:00
parent 9ac4a940dd
commit 3f6c186c13
9 changed files with 203 additions and 13 deletions

View File

@ -184,6 +184,10 @@
"settingsBackgroundImageClearDescription": "Reset the background image to blank.", "settingsBackgroundImageClearDescription": "Reset the background image to blank.",
"settingsThemeMaterial3": "Use Material You Design", "settingsThemeMaterial3": "Use Material You Design",
"settingsThemeMaterial3Description": "Set the application theme to Material 3 Design.", "settingsThemeMaterial3Description": "Set the application theme to Material 3 Design.",
"settingsColorScheme": "Color Scheme",
"settingsColorSchemeDescription": "Set the application primary color.",
"settingsColorSeed": "Color Seed",
"settingsColorSeedDescription": "Select one of the present color schemes.",
"settingsNetwork": "Network", "settingsNetwork": "Network",
"settingsNetworkServer": "HyperNet Server", "settingsNetworkServer": "HyperNet Server",
"settingsNetworkServerDescription": "Set the HyperNet server address, choose ours or build your own.", "settingsNetworkServerDescription": "Set the HyperNet server address, choose ours or build your own.",
@ -450,7 +454,7 @@
"publisherBlockHintDescription": "You are going to block this publisher's maintainer, this will also block publishers that run by the same user.", "publisherBlockHintDescription": "You are going to block this publisher's maintainer, this will also block publishers that run by the same user.",
"userUnblocked": "{} has been unblocked.", "userUnblocked": "{} has been unblocked.",
"userBlocked": "{} has been blocked.", "userBlocked": "{} has been blocked.",
"postSharingViaPicture": "Capturing post as picture, please stand by...", "postSharingViaPicture": "Capturing post as picture, please wait...",
"postImageShareReadMore": "Scan the QR code to read full post", "postImageShareReadMore": "Scan the QR code to read full post",
"postImageShareAds": "Explore posts on the Solar Network", "postImageShareAds": "Explore posts on the Solar Network",
"postShare": "Share", "postShare": "Share",
@ -461,5 +465,15 @@
"shareIntentDescription": "What do you want to do with the content you are sharing?", "shareIntentDescription": "What do you want to do with the content you are sharing?",
"shareIntentPostStory": "Post a Story", "shareIntentPostStory": "Post a Story",
"updateAvailable": "Update Available", "updateAvailable": "Update Available",
"updateOngoing": "正在更新,请稍后..." "updateOngoing": "Updating, please wait...",
"custom": "Custom",
"colorSchemeIndigo": "Indigo",
"colorSchemeBlue": "Blue",
"colorSchemeGreen": "Green",
"colorSchemeYellow": "Yellow",
"colorSchemeOrange": "Orange",
"colorSchemeRed": "Red",
"colorSchemeWhite": "White",
"colorSchemeBlack": "Black",
"colorSchemeApplied": "Color scheme has been applied, may need restart the app to take effect."
} }

View File

@ -182,6 +182,10 @@
"settingsBackgroundImageClearDescription": "将应用背景图重置为空白。", "settingsBackgroundImageClearDescription": "将应用背景图重置为空白。",
"settingsThemeMaterial3": "使用 Material You 设计范式", "settingsThemeMaterial3": "使用 Material You 设计范式",
"settingsThemeMaterial3Description": "将应用主题设置为 Material 3 设计范式的主题。", "settingsThemeMaterial3Description": "将应用主题设置为 Material 3 设计范式的主题。",
"settingsColorScheme": "主题色",
"settingsColorSchemeDescription": "设置应用主题色。",
"settingsColorSeed": "预设色彩主题",
"settingsColorSeedDescription": "选择一个预设色彩主题。",
"settingsNetwork": "网络", "settingsNetwork": "网络",
"settingsNetworkServer": "HyperNet 服务器", "settingsNetworkServer": "HyperNet 服务器",
"settingsNetworkServerDescription": "设置 HyperNet 服务器地址,选择我们提供的,或者自己搭建。", "settingsNetworkServerDescription": "设置 HyperNet 服务器地址,选择我们提供的,或者自己搭建。",
@ -459,5 +463,15 @@
"shareIntentDescription": "您想对您分享的内容做些什么?", "shareIntentDescription": "您想对您分享的内容做些什么?",
"shareIntentPostStory": "发布动态", "shareIntentPostStory": "发布动态",
"updateAvailable": "检测到更新可用", "updateAvailable": "检测到更新可用",
"updateOngoing": "正在更新,请稍后……" "updateOngoing": "正在更新,请稍后……",
"custom": "自定义",
"colorSchemeIndigo": "靛蓝",
"colorSchemeBlue": "蓝色",
"colorSchemeGreen": "绿色",
"colorSchemeYellow": "黄色",
"colorSchemeOrange": "橙色",
"colorSchemeRed": "红色",
"colorSchemeWhite": "白色",
"colorSchemeBlack": "黑色",
"colorSchemeApplied": "主题色已应用,可能需要重启来生效。"
} }

View File

@ -123,6 +123,8 @@
"fieldPostTitle": "標題", "fieldPostTitle": "標題",
"fieldPostDescription": "描述", "fieldPostDescription": "描述",
"fieldPostTags": "標籤", "fieldPostTags": "標籤",
"fieldPostAlias": "別名",
"fieldPostAliasHint": "可選項,用於在 URL 中表示該帖子,應遵循 URL-Safe 的原則。",
"postPublish": "發佈", "postPublish": "發佈",
"postPublishedAt": "發佈於", "postPublishedAt": "發佈於",
"postPublishedUntil": "取消發佈於", "postPublishedUntil": "取消發佈於",
@ -180,6 +182,10 @@
"settingsBackgroundImageClearDescription": "將應用背景圖重置為空白。", "settingsBackgroundImageClearDescription": "將應用背景圖重置為空白。",
"settingsThemeMaterial3": "使用 Material You 設計範式", "settingsThemeMaterial3": "使用 Material You 設計範式",
"settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。", "settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。",
"settingsColorScheme": "主題色",
"settingsColorSchemeDescription": "設置應用主題色。",
"settingsColorSeed": "預設色彩主題",
"settingsColorSeedDescription": "選擇一個預設色彩主題。",
"settingsNetwork": "網絡", "settingsNetwork": "網絡",
"settingsNetworkServer": "HyperNet 服務器", "settingsNetworkServer": "HyperNet 服務器",
"settingsNetworkServerDescription": "設置 HyperNet 服務器地址,選擇我們提供的,或者自己搭建。", "settingsNetworkServerDescription": "設置 HyperNet 服務器地址,選擇我們提供的,或者自己搭建。",
@ -368,6 +374,8 @@
"dailyCheckNegativeHint6": "出門", "dailyCheckNegativeHint6": "出門",
"dailyCheckNegativeHint6Description": "忘帶傘遇上大雨", "dailyCheckNegativeHint6Description": "忘帶傘遇上大雨",
"happyBirthday": "生日快樂,{}", "happyBirthday": "生日快樂,{}",
"celebrateMerryXmas": "聖誕快樂,{}",
"celebrateNewYear": "新年快樂,{}",
"friendNew": "添加好友", "friendNew": "添加好友",
"friendRequests": "好友請求", "friendRequests": "好友請求",
"friendRequestsDescription": { "friendRequestsDescription": {
@ -453,5 +461,17 @@
"poweredBy": "由 {} 提供支持", "poweredBy": "由 {} 提供支持",
"shareIntent": "分享", "shareIntent": "分享",
"shareIntentDescription": "您想對您分享的內容做些什麼?", "shareIntentDescription": "您想對您分享的內容做些什麼?",
"shareIntentPostStory": "發佈動態" "shareIntentPostStory": "發佈動態",
"updateAvailable": "檢測到更新可用",
"updateOngoing": "正在更新,請稍後……",
"custom": "自定義",
"colorSchemeIndigo": "靛藍",
"colorSchemeBlue": "藍色",
"colorSchemeGreen": "綠色",
"colorSchemeYellow": "黃色",
"colorSchemeOrange": "橙色",
"colorSchemeRed": "紅色",
"colorSchemeWhite": "白色",
"colorSchemeBlack": "黑色",
"colorSchemeApplied": "主題色已應用,可能需要重啓來生效。"
} }

View File

@ -123,6 +123,8 @@
"fieldPostTitle": "標題", "fieldPostTitle": "標題",
"fieldPostDescription": "描述", "fieldPostDescription": "描述",
"fieldPostTags": "標籤", "fieldPostTags": "標籤",
"fieldPostAlias": "別名",
"fieldPostAliasHint": "可選項,用於在 URL 中表示該帖子,應遵循 URL-Safe 的原則。",
"postPublish": "釋出", "postPublish": "釋出",
"postPublishedAt": "釋出於", "postPublishedAt": "釋出於",
"postPublishedUntil": "取消釋出於", "postPublishedUntil": "取消釋出於",
@ -180,6 +182,10 @@
"settingsBackgroundImageClearDescription": "將應用背景圖重置為空白。", "settingsBackgroundImageClearDescription": "將應用背景圖重置為空白。",
"settingsThemeMaterial3": "使用 Material You 設計正規化", "settingsThemeMaterial3": "使用 Material You 設計正規化",
"settingsThemeMaterial3Description": "將應用主題設定為 Material 3 設計正規化的主題。", "settingsThemeMaterial3Description": "將應用主題設定為 Material 3 設計正規化的主題。",
"settingsColorScheme": "主題色",
"settingsColorSchemeDescription": "設定應用主題色。",
"settingsColorSeed": "預設色彩主題",
"settingsColorSeedDescription": "選擇一個預設色彩主題。",
"settingsNetwork": "網路", "settingsNetwork": "網路",
"settingsNetworkServer": "HyperNet 伺服器", "settingsNetworkServer": "HyperNet 伺服器",
"settingsNetworkServerDescription": "設定 HyperNet 伺服器地址,選擇我們提供的,或者自己搭建。", "settingsNetworkServerDescription": "設定 HyperNet 伺服器地址,選擇我們提供的,或者自己搭建。",
@ -368,6 +374,8 @@
"dailyCheckNegativeHint6": "出門", "dailyCheckNegativeHint6": "出門",
"dailyCheckNegativeHint6Description": "忘帶傘遇上大雨", "dailyCheckNegativeHint6Description": "忘帶傘遇上大雨",
"happyBirthday": "生日快樂,{}", "happyBirthday": "生日快樂,{}",
"celebrateMerryXmas": "聖誕快樂,{}",
"celebrateNewYear": "新年快樂,{}",
"friendNew": "新增好友", "friendNew": "新增好友",
"friendRequests": "好友請求", "friendRequests": "好友請求",
"friendRequestsDescription": { "friendRequestsDescription": {
@ -453,5 +461,17 @@
"poweredBy": "由 {} 提供支援", "poweredBy": "由 {} 提供支援",
"shareIntent": "分享", "shareIntent": "分享",
"shareIntentDescription": "您想對您分享的內容做些什麼?", "shareIntentDescription": "您想對您分享的內容做些什麼?",
"shareIntentPostStory": "釋出動態" "shareIntentPostStory": "釋出動態",
"updateAvailable": "檢測到更新可用",
"updateOngoing": "正在更新,請稍後……",
"custom": "自定義",
"colorSchemeIndigo": "靛藍",
"colorSchemeBlue": "藍色",
"colorSchemeGreen": "綠色",
"colorSchemeYellow": "黃色",
"colorSchemeOrange": "橙色",
"colorSchemeRed": "紅色",
"colorSchemeWhite": "白色",
"colorSchemeBlack": "黑色",
"colorSchemeApplied": "主題色已應用,可能需要重啟來生效。"
} }

View File

@ -1,3 +1,5 @@
import 'dart:ui';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:surface/theme.dart'; import 'package:surface/theme.dart';
@ -11,8 +13,8 @@ class ThemeProvider extends ChangeNotifier {
}); });
} }
void reloadTheme({bool? useMaterial3}) { void reloadTheme({Color? seedColorOverride, bool? useMaterial3}) {
createAppThemeSet().then((value) { createAppThemeSet(seedColorOverride: seedColorOverride, useMaterial3: useMaterial3).then((value) {
theme = value; theme = value;
notifyListeners(); notifyListeners();
}); });

View File

@ -5,6 +5,7 @@ import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
@ -18,6 +19,17 @@ import 'package:surface/providers/theme.dart';
import 'package:surface/theme.dart'; import 'package:surface/theme.dart';
import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/dialog.dart';
const Map<String, Color> kColorSchemes = {
'colorSchemeIndigo': Colors.indigo,
'colorSchemeBlue': Colors.blue,
'colorSchemeGreen': Colors.green,
'colorSchemeYellow': Colors.yellow,
'colorSchemeOrange': Colors.orange,
'colorSchemeRed': Colors.red,
'colorSchemeWhite': Colors.white,
'colorSchemeBlack': Colors.black,
};
class SettingsScreen extends StatefulWidget { class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key}); const SettingsScreen({super.key});
@ -77,7 +89,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
if (image == null) return; if (image == null) return;
await File(image.path).copy('$_docBasepath/app_background_image'); await File(image.path).copy('$_docBasepath/app_background_image');
_prefs.setBool('has_background_image', true); _prefs.setBool('app_has_background', true);
setState(() {}); setState(() {});
}, },
@ -98,7 +110,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
trailing: const Icon(Symbols.chevron_right), trailing: const Icon(Symbols.chevron_right),
onTap: () { onTap: () {
File('$_docBasepath/app_background_image').deleteSync(); File('$_docBasepath/app_background_image').deleteSync();
_prefs.remove('has_background_image'); _prefs.remove('app_has_background');
setState(() {}); setState(() {});
}, },
); );
@ -120,6 +132,101 @@ class _SettingsScreenState extends State<SettingsScreen> {
th.reloadTheme(useMaterial3: value ?? false); th.reloadTheme(useMaterial3: value ?? false);
}, },
), ),
ListTile(
leading: const Icon(Symbols.format_paint),
title: Text('settingsColorScheme').tr(),
subtitle: Text('settingsColorSchemeDescription').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
trailing: const Icon(Symbols.chevron_right),
onTap: () async {
Color pickerColor = Color(_prefs.getInt('app_color_scheme') ?? Colors.indigo.value);
final color = await showDialog<Color?>(
context: context,
builder: (context) => AlertDialog(
content: SingleChildScrollView(
child: ColorPicker(
pickerColor: pickerColor,
onColorChanged: (color) => pickerColor = color,
enableAlpha: false,
hexInputBar: true,
),
),
actions: <Widget>[
TextButton(
child: const Text('dialogDismiss').tr(),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('dialogConfirm').tr(),
onPressed: () {
Navigator.of(context).pop(pickerColor);
},
),
],
),
);
if (color == null || !context.mounted) return;
_prefs.setInt('app_color_scheme', color.value);
final th = context.read<ThemeProvider>();
th.reloadTheme(seedColorOverride: color);
setState(() {});
context.showSnackbar('colorSchemeApplied'.tr());
},
),
ListTile(
leading: const Icon(Symbols.palette),
title: Text('settingsColorSeed').tr(),
subtitle: Text('settingsColorSeedDescription').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
trailing: DropdownButtonHideUnderline(
child: DropdownButton2<int?>(
isExpanded: true,
items: [
...kColorSchemes.entries.mapIndexed((idx, ele) {
return DropdownMenuItem<int>(
value: idx,
child: Text(ele.key).tr(),
);
}),
DropdownMenuItem<int>(
value: -1,
child: Text('custom').tr(),
),
],
value: _prefs.getInt('app_color_scheme') == null
? 1
: kColorSchemes.values
.toList()
.indexWhere((ele) => ele.value == _prefs.getInt('app_color_scheme')),
onChanged: (int? value) {
if (value != null && value != -1) {
_prefs.setInt('app_color_scheme', kColorSchemes.values.elementAt(value).value);
final th = context.watch<ThemeProvider>();
th.reloadTheme(seedColorOverride: kColorSchemes.values.elementAt(value));
setState(() {});
context.showSnackbar('colorSchemeApplied'.tr());
}
},
buttonStyleData: const ButtonStyleData(
padding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 5,
),
height: 40,
width: 160,
),
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
),
),
),
], ],
), ),
Column( Column(
@ -189,7 +296,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
horizontal: 16, horizontal: 16,
vertical: 5, vertical: 5,
), ),
height: 40, height: 56,
width: 160, width: 160,
), ),
menuItemStyleData: const MenuItemStyleData( menuItemStyleData: const MenuItemStyleData(

View File

@ -10,7 +10,7 @@ class ThemeSet {
ThemeSet({required this.light, required this.dark}); ThemeSet({required this.light, required this.dark});
} }
Future<ThemeSet> createAppThemeSet({bool? useMaterial3}) async { Future<ThemeSet> createAppThemeSet({Color? seedColorOverride, bool? useMaterial3}) async {
return ThemeSet( return ThemeSet(
light: await createAppTheme(Brightness.light, useMaterial3: useMaterial3), light: await createAppTheme(Brightness.light, useMaterial3: useMaterial3),
dark: await createAppTheme(Brightness.dark, useMaterial3: useMaterial3), dark: await createAppTheme(Brightness.dark, useMaterial3: useMaterial3),
@ -19,16 +19,20 @@ Future<ThemeSet> createAppThemeSet({bool? useMaterial3}) async {
Future<ThemeData> createAppTheme( Future<ThemeData> createAppTheme(
Brightness brightness, { Brightness brightness, {
Color? seedColorOverride,
bool? useMaterial3, bool? useMaterial3,
}) async { }) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final seedColorString = prefs.getInt('app_color_scheme');
final seedColor = seedColorString != null ? Color(seedColorString) : Colors.indigo;
final colorScheme = ColorScheme.fromSeed( final colorScheme = ColorScheme.fromSeed(
seedColor: Colors.indigo, seedColor: seedColorOverride ?? seedColor,
brightness: brightness, brightness: brightness,
); );
final hasBackground = prefs.getBool('has_background_image') ?? false; final hasBackground = prefs.getBool('app_has_background') ?? false;
return ThemeData( return ThemeData(
useMaterial3: useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? false), useMaterial3: useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? false),

View File

@ -643,6 +643,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.1" version: "3.4.1"
flutter_colorpicker:
dependency: "direct main"
description:
name: flutter_colorpicker
sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter_context_menu: flutter_context_menu:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -111,6 +111,7 @@ dependencies:
flutter_app_update: ^3.2.2 flutter_app_update: ^3.2.2
in_app_review: ^2.0.10 in_app_review: ^2.0.10
version: ^3.0.2 version: ^3.0.2
flutter_colorpicker: ^1.1.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: