Add full black theme

This commit is contained in:
niuhuan 2022-03-23 18:51:38 +08:00
parent f5dbbe4c4e
commit cae29f23bb
10 changed files with 256 additions and 140 deletions

View File

@ -1,6 +1,7 @@
PIKAPIKA - 漫画客户端 PIKAPIKA - 漫画客户端
======== ========
[![license](https://img.shields.io/github/license/niuhuan/pikapika)](https://raw.githubusercontent.com/niuhuan/pikapika/master/LICENSE) [![license](https://img.shields.io/github/license/niuhuan/pikapika)](https://raw.githubusercontent.com/niuhuan/pikapika/master/LICENSE)
[![ci-release](https://img.shields.io/github/workflow/status/niuhuan/pikapika/Release)](https://github.com/niuhuan/pikapika/releases)
[![releases](https://img.shields.io/github/v/release/niuhuan/pikapika)](https://github.com/niuhuan/pikapika/releases) [![releases](https://img.shields.io/github/v/release/niuhuan/pikapika)](https://github.com/niuhuan/pikapika/releases)
[![downloads](https://img.shields.io/github/downloads/niuhuan/pikapika/total)](https://github.com/niuhuan/pikapika/releases) [![downloads](https://img.shields.io/github/downloads/niuhuan/pikapika/total)](https://github.com/niuhuan/pikapika/releases)

View File

@ -1 +1 @@
v1.4.2 v1.4.3

View File

@ -1 +1,2 @@
测试RELEASE - [x] 增加纯黑主题
- [x] 设置点击屏幕一次为默认的全屏方式

View File

@ -28,7 +28,7 @@ late FullScreenAction _fullScreenAction;
Future<void> initFullScreenAction() async { Future<void> initFullScreenAction() async {
_fullScreenAction = _fullScreenActionFromString(await method.loadProperty( _fullScreenAction = _fullScreenActionFromString(await method.loadProperty(
_propertyName, _propertyName,
FullScreenAction.CONTROLLER.toString(), FullScreenAction.TOUCH_ONCE.toString(),
)); ));
} }

View File

@ -7,7 +7,6 @@ import 'package:pikapika/basic/Common.dart';
import '../Method.dart'; import '../Method.dart';
import 'Platform.dart'; import 'Platform.dart';
// //
const _fontFamilyProperty = "fontFamily"; const _fontFamilyProperty = "fontFamily";
@ -28,13 +27,17 @@ ThemeData _fontThemeData(bool dark) {
Future<void> inputFont(BuildContext context) async { Future<void> inputFont(BuildContext context) async {
var font = await displayTextInputDialog( var font = await displayTextInputDialog(
context, src: "$_fontFamily", title: "字体", hint: "请输入字体", context,
desc: "请输入字体的名称, 例如宋体/黑体, 如果您保存后没有发生变化, 说明字体无法使用或名称错误, 可以去参考C:\\Windows\\Fonts寻找您的字体。", src: "$_fontFamily",
title: "字体",
hint: "请输入字体",
desc:
"请输入字体的名称, 例如宋体/黑体, 如果您保存后没有发生变化, 说明字体无法使用或名称错误, 可以去参考C:\\Windows\\Fonts寻找您的字体。",
); );
if (font != null) { if (font != null) {
await method.saveProperty(_fontFamilyProperty, font); await method.saveProperty(_fontFamilyProperty, font);
_fontFamily = font; _fontFamily = font;
_changeThemeByCode(_themeCode); _reloadTheme();
} }
} }
@ -62,6 +65,8 @@ abstract class _ThemePackage {
String name(); String name();
ThemeData themeData(ThemeData rawData); ThemeData themeData(ThemeData rawData);
bool isDark();
} }
class _OriginTheme extends _ThemePackage { class _OriginTheme extends _ThemePackage {
@ -73,6 +78,9 @@ class _OriginTheme extends _ThemePackage {
@override @override
ThemeData themeData(ThemeData rawData) => rawData; ThemeData themeData(ThemeData rawData) => rawData;
@override
bool isDark() => false;
} }
class _PinkTheme extends _ThemePackage { class _PinkTheme extends _ThemePackage {
@ -83,8 +91,7 @@ class _PinkTheme extends _ThemePackage {
String name() => "粉色"; String name() => "粉色";
@override @override
ThemeData themeData(ThemeData rawData) => ThemeData themeData(ThemeData rawData) => rawData.copyWith(
rawData.copyWith(
brightness: Brightness.light, brightness: Brightness.light,
colorScheme: ColorScheme.light( colorScheme: ColorScheme.light(
secondary: Colors.pink.shade200, secondary: Colors.pink.shade200,
@ -113,6 +120,9 @@ class _PinkTheme extends _ThemePackage {
), ),
), ),
); );
@override
bool isDark() => false;
} }
class _BlackTheme extends _ThemePackage { class _BlackTheme extends _ThemePackage {
@ -123,8 +133,7 @@ class _BlackTheme extends _ThemePackage {
String name() => "酷黑"; String name() => "酷黑";
@override @override
ThemeData themeData(ThemeData rawData) => ThemeData themeData(ThemeData rawData) => rawData.copyWith(
rawData.copyWith(
brightness: Brightness.light, brightness: Brightness.light,
colorScheme: ColorScheme.light( colorScheme: ColorScheme.light(
secondary: Colors.pink.shade200, secondary: Colors.pink.shade200,
@ -154,6 +163,9 @@ class _BlackTheme extends _ThemePackage {
), ),
), ),
); );
@override
bool isDark() => false;
} }
class _DarkTheme extends _ThemePackage { class _DarkTheme extends _ThemePackage {
@ -164,8 +176,7 @@ class _DarkTheme extends _ThemePackage {
String name() => "暗黑"; String name() => "暗黑";
@override @override
ThemeData themeData(ThemeData rawData) => ThemeData themeData(ThemeData rawData) => rawData.copyWith(
rawData.copyWith(
brightness: Brightness.light, brightness: Brightness.light,
colorScheme: ColorScheme.light( colorScheme: ColorScheme.light(
secondary: Colors.pink.shade200, secondary: Colors.pink.shade200,
@ -194,6 +205,9 @@ class _DarkTheme extends _ThemePackage {
), ),
), ),
); );
@override
bool isDark() => true;
} }
class _DustyBlueTheme extends _ThemePackage { class _DustyBlueTheme extends _ThemePackage {
@ -204,13 +218,14 @@ class _DustyBlueTheme extends _ThemePackage {
String name() => "灰蓝"; String name() => "灰蓝";
@override @override
ThemeData themeData(ThemeData rawData) => ThemeData themeData(ThemeData rawData) => rawData.copyWith(
rawData.copyWith(
scaffoldBackgroundColor: Color.alphaBlend( scaffoldBackgroundColor: Color.alphaBlend(
const Color(0x11999999), const Color(0xff20253b), const Color(0x11999999),
const Color(0xff20253b),
), ),
cardColor: Color.alphaBlend( cardColor: Color.alphaBlend(
const Color(0x11AAAAAA), const Color(0xff20253b), const Color(0x11AAAAAA),
const Color(0xff20253b),
), ),
brightness: Brightness.light, brightness: Brightness.light,
colorScheme: ColorScheme.light( colorScheme: ColorScheme.light(
@ -244,153 +259,182 @@ class _DustyBlueTheme extends _ThemePackage {
), ),
), ),
); );
@override
bool isDark() => true;
} }
var _darkTheme = _DarkTheme(); class _DarkBlackTheme extends _ThemePackage {
var _dustyBlueTheme = _DustyBlueTheme(); @override
String code() => "dark_black";
@override
String name() => "纯黑";
@override
ThemeData themeData(ThemeData rawData) => rawData.copyWith(
brightness: Brightness.light,
colorScheme: ColorScheme.light(
secondary: Colors.pink.shade200,
),
scaffoldBackgroundColor: Colors.black,
appBarTheme: const AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle.light,
color: Color.fromARGB(0xff, 10, 10, 10),
iconTheme: IconThemeData(
color: Colors.white,
),
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey.shade300,
backgroundColor: const Color.fromARGB(0xff, 10, 10, 10),
),
primaryColor: Colors.pink.shade200,
textSelectionTheme: TextSelectionThemeData(
cursorColor: Colors.pink.shade200,
selectionColor: Colors.pink.shade300.withAlpha(150),
selectionHandleColor: Colors.pink.shade300.withAlpha(200),
),
inputDecorationTheme: InputDecorationTheme(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.pink.shade200),
),
),
dividerColor: const Color.fromARGB(0xff, 64, 64, 64),
);
@override
bool isDark() => true;
}
final _themePackages = <_ThemePackage>[ final _themePackages = <_ThemePackage>[
_OriginTheme(), _OriginTheme(),
_PinkTheme(), _PinkTheme(),
_BlackTheme(), _BlackTheme(),
_darkTheme, _DarkTheme(),
_dustyBlueTheme, _DustyBlueTheme(),
_DarkBlackTheme(),
]; ];
// //
var themeEvent = Event<EventArgs>(); var themeEvent = Event<EventArgs>();
const _themePropertyName = "theme"; const _nightModePropertyName = "androidNightMode";
const _defaultThemeCode = "pink"; const _lightThemePropertyName = "theme";
const _darkThemePropertyName = "theme.dark";
const _defaultLightThemeCode = "pink";
const _defaultDarkThemeCode = "dark";
bool androidNightModeDisplay = false;
bool androidNightMode = false;
String? _themeCode; String? _lightThemeCode;
ThemeData? _themeData; ThemeData? _lightThemeData;
ThemeData? _currentDarkTheme; String? _darkThemeCode;
bool _androidNightMode = false; ThemeData? _darkThemeData;
String currentThemeName() { // _changeThemeByCode
String _codeToName(String? code) {
for (var package in _themePackages) { for (var package in _themePackages) {
if (_themeCode == package.code()) { if (code == package.code()) {
return package.name(); return package.name();
} }
} }
return ""; return "";
} }
ThemeData? currentThemeData() { String currentLightThemeName() {
return _themeData; return _codeToName(_lightThemeCode);
} }
ThemeData? currentDarkTheme() { String currentDarkThemeName() {
return _currentDarkTheme; return _codeToName(_darkThemeCode);
}
ThemeData? currentLightThemeData() {
return _lightThemeData;
}
ThemeData? currentDarkThemeData() {
return _darkThemeData;
} }
// Code选择主题, // Code选择主题,
void _changeThemeByCode(String? themeCode) {
_ThemePackage? _themePackage; ThemeData? _themeByCode(String? themeCode) {
for (var package in _themePackages) { for (var package in _themePackages) {
if (themeCode == package.code()) { if (themeCode == package.code()) {
_themeCode = themeCode; return package.themeData(_fontThemeData(package.isDark()));
_themePackage = package;
break;
} }
} }
if (_themePackage != null) { return null;
_themeData = _themePackage.themeData( }
_fontThemeData(
_themePackage == _darkTheme || _themePackage == _dustyBlueTheme), void _reloadTheme() {
); _lightThemeData = _themeByCode(_lightThemeCode);
if (androidNightMode) {
_darkThemeData = _themeByCode(_darkThemeCode);
} else {
_darkThemeData = _lightThemeData;
} }
_currentDarkTheme = _androidNightMode
? _darkTheme.themeData(_fontThemeData(true))
: _themeData;
themeEvent.broadcast(); themeEvent.broadcast();
} }
//
const _nightModePropertyName = "androidNightMode";
Future<dynamic> initTheme() async { Future<dynamic> initTheme() async {
_androidNightMode = androidNightModeDisplay = androidVersion >= 29;
androidNightMode =
await method.loadProperty(_nightModePropertyName, "true") == "true"; await method.loadProperty(_nightModePropertyName, "true") == "true";
_changeThemeByCode( _lightThemeCode = await method.loadProperty(
await method.loadProperty(_themePropertyName, _defaultThemeCode), _lightThemePropertyName, _defaultLightThemeCode);
); _darkThemeCode =
await method.loadProperty(_darkThemePropertyName, _defaultDarkThemeCode);
_reloadTheme();
} }
// //
Future<dynamic> chooseTheme(BuildContext buildContext) async { Future<String?> _chooseTheme(BuildContext buildContext) {
String? theme = await showDialog<String>( return showDialog<String>(
context: buildContext, context: buildContext,
builder: (BuildContext context) { builder: (BuildContext context) {
return StatefulBuilder( return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) { builder: (BuildContext context, StateSetter setState) {
var list = <SimpleDialogOption>[]; var list = <SimpleDialogOption>[];
if (androidVersion >= 29) { list.addAll(_themePackages.map((e) => SimpleDialogOption(
var onChange = (bool? v) async { child: Text(e.name()),
if (v != null) { onPressed: () {
await method.saveProperty( Navigator.of(context).pop(e.code());
_nightModePropertyName, "$v"); },
_androidNightMode = v; )));
} return SimpleDialog(
_changeThemeByCode(_themeCode); title: const Text("选择主题"),
}; children: list,
list.add( );
SimpleDialogOption( });
child: GestureDetector(
onTap: () {
onChange(!_androidNightMode);
},
child: Container(
margin: const EdgeInsets.only(top: 3, bottom: 3),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Theme
.of(context)
.dividerColor,
width: 0.5,
),
bottom: BorderSide(
color: Theme
.of(context)
.dividerColor,
width: 0.5
),
),
),
child: Row(
children: [
Checkbox(
value: _androidNightMode,
onChanged: onChange,
),
const Text("随手机进入黑暗模式"),
],
),
),
),
),
);
}
list.addAll(_themePackages
.map((e) =>
SimpleDialogOption(
child: Text(e.name()),
onPressed: () {
Navigator.of(context).pop(e.code());
},
)
));
return SimpleDialog(
title: const Text("选择主题"),
children: list,
);
})
}, },
); );
}
Future<dynamic> chooseLightTheme(BuildContext buildContext) async {
String? theme = await _chooseTheme(buildContext);
if (theme != null) { if (theme != null) {
method.saveProperty(_themePropertyName, theme); await method.saveProperty(_lightThemePropertyName, theme);
_changeThemeByCode(theme); _lightThemeCode = theme;
_reloadTheme();
} }
} }
Future<dynamic> chooseDarkTheme(BuildContext buildContext) async {
String? theme = await _chooseTheme(buildContext);
if (theme != null) {
await method.saveProperty(_darkThemePropertyName, theme);
_darkThemeCode = theme;
_reloadTheme();
}
}
Future setAndroidNightMode(bool value) async {
await method.saveProperty(_nightModePropertyName, "$value");
androidNightMode = value;
_reloadTheme();
}

View File

@ -38,8 +38,8 @@ class _PikapikaAppState extends State<PikapikaApp> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
scrollBehavior: mouseAndTouchScrollBehavior, scrollBehavior: mouseAndTouchScrollBehavior,
theme: currentThemeData(), theme: currentLightThemeData(),
darkTheme: currentDarkTheme(), darkTheme: currentDarkThemeData(),
navigatorObservers: [navigatorObserver, routeObserver], navigatorObservers: [navigatorObserver, routeObserver],
home: const InitScreen(), home: const InitScreen(),
); );

View File

@ -60,7 +60,7 @@ class _AccountScreenState extends State<AccountScreen> {
actions: [ actions: [
IconButton( IconButton(
onPressed: () { onPressed: () {
chooseTheme(context); // todo : chooseTheme(context);
}, },
icon: const Text('主题'), icon: const Text('主题'),
), ),

View File

@ -1,14 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pikapika/basic/Common.dart'; import 'package:pikapika/basic/Common.dart';
import 'package:pikapika/basic/config/Themes.dart';
import 'package:pikapika/basic/config/Version.dart'; import 'package:pikapika/basic/config/Version.dart';
import 'package:pikapika/screens/AboutScreen.dart'; import 'package:pikapika/screens/AboutScreen.dart';
import 'package:pikapika/screens/AccountScreen.dart'; import 'package:pikapika/screens/AccountScreen.dart';
import 'package:pikapika/screens/DownloadListScreen.dart'; import 'package:pikapika/screens/DownloadListScreen.dart';
import 'package:pikapika/screens/FavouritePaperScreen.dart'; import 'package:pikapika/screens/FavouritePaperScreen.dart';
import 'package:pikapika/screens/ThemeScreen.dart';
import 'package:pikapika/screens/ViewLogsScreen.dart'; import 'package:pikapika/screens/ViewLogsScreen.dart';
import 'package:pikapika/basic/Method.dart'; import 'package:pikapika/basic/Method.dart';
import '../basic/config/Themes.dart';
import 'SettingsScreen.dart'; import 'SettingsScreen.dart';
import 'components/Badge.dart'; import 'components/Badge.dart';
import 'components/UserProfileCard.dart'; import 'components/UserProfileCard.dart';
@ -17,13 +18,11 @@ import 'components/UserProfileCard.dart';
class SpaceScreen extends StatefulWidget { class SpaceScreen extends StatefulWidget {
const SpaceScreen({Key? key}) : super(key: key); const SpaceScreen({Key? key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => _SpaceScreenState(); State<StatefulWidget> createState() => _SpaceScreenState();
} }
class _SpaceScreenState extends State<SpaceScreen> { class _SpaceScreenState extends State<SpaceScreen> {
@override @override
void initState() { void initState() {
versionEvent.subscribe(_onVersion); versionEvent.subscribe(_onVersion);
@ -44,7 +43,7 @@ class _SpaceScreenState extends State<SpaceScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('我的'), title: const Text('我的'),
actions: [ actions: [
IconButton( IconButton(
onPressed: () async { onPressed: () async {
@ -55,7 +54,8 @@ class _SpaceScreenState extends State<SpaceScreen> {
await method.setPassword(""); await method.setPassword("");
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
MaterialPageRoute(builder: (context) => AccountScreen()), MaterialPageRoute(
builder: (context) => const AccountScreen()),
); );
} }
}, },
@ -91,38 +91,45 @@ class _SpaceScreenState extends State<SpaceScreen> {
const Divider(), const Divider(),
ListTile( ListTile(
onTap: () async { onTap: () async {
await chooseTheme(context); if (androidNightModeDisplay) {
setState(() {}); Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ThemeScreen()),
);
} else {
chooseLightTheme(context);
}
}, },
title: Text('主题'), title: const Text('主题'),
subtitle: Text(currentThemeName()),
), ),
const Divider(), const Divider(),
ListTile( ListTile(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => FavouritePaperScreen()), MaterialPageRoute(
builder: (context) => const FavouritePaperScreen()),
); );
}, },
title: Text('我的收藏'), title: const Text('我的收藏'),
), ),
const Divider(), const Divider(),
ListTile( ListTile(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => ViewLogsScreen()), MaterialPageRoute(builder: (context) => const ViewLogsScreen()),
); );
}, },
title: Text('浏览记录'), title: const Text('浏览记录'),
), ),
const Divider(), const Divider(),
ListTile( ListTile(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => const DownloadListScreen()), MaterialPageRoute(
builder: (context) => const DownloadListScreen()),
); );
}, },
title: const Text('我的下载'), title: const Text('我的下载'),

View File

@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import '../basic/config/Themes.dart';
import 'components/RightClickPop.dart';
class ThemeScreen extends StatefulWidget {
const ThemeScreen({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _ThemeScreenState();
}
class _ThemeScreenState extends State<ThemeScreen> {
@override
Widget build(BuildContext context) {
return RightClickPop(buildScreen(context));
}
Widget buildScreen(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("主题设置")),
body: ListView(
children: [
const Divider(),
ListTile(
onTap: () async {
await chooseLightTheme(context);
setState(() {});
},
title: const Text('主题'),
subtitle: Text(currentLightThemeName()),
),
const Divider(),
...androidNightModeDisplay
? [
SwitchListTile(
title: const Text("深色模式下使用不同的主题"),
value: androidNightMode,
onChanged: (value) async {
await setAndroidNightMode(value);
setState(() {});
}),
]
: [],
const Divider(),
...androidNightModeDisplay && androidNightMode
? [
ListTile(
onTap: () async {
await chooseDarkTheme(context);
setState(() {});
},
title: const Text('主题 (深色模式)'),
subtitle: Text(currentDarkThemeName()),
),
]
: [],
const Divider(),
],
),
);
}
}

View File

@ -494,7 +494,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.4.4"
xml: xml:
dependency: transitive dependency: transitive
description: description: