mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-17 23:56:13 +08:00
feat: reduce luminosity in dark mode (#988)
This commit is contained in:
committed by
GitHub
parent
88c2ba8059
commit
dc61d9007f
@@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
void showConfirmDialog({
|
Future<void> showConfirmDialog({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required String title,
|
required String title,
|
||||||
dynamic content,
|
dynamic content,
|
||||||
required VoidCallback onConfirm,
|
required VoidCallback onConfirm,
|
||||||
}) {
|
}) {
|
||||||
showDialog(
|
return showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ Widget imageView(
|
|||||||
src: item.url,
|
src: item.url,
|
||||||
width: imageWidth,
|
width: imageWidth,
|
||||||
height: imageHeight,
|
height: imageHeight,
|
||||||
isLongPic: () => item.isLongPic,
|
isLongPic: item.isLongPic,
|
||||||
callback: () => item.width <= item.height,
|
forceUseCacheWidth: item.width <= item.height,
|
||||||
getPlaceHolder: () {
|
getPlaceHolder: () {
|
||||||
return Container(
|
return Container(
|
||||||
width: imageWidth,
|
width: imageWidth,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/models/common/image_type.dart';
|
import 'package:PiliPlus/models/common/image_type.dart';
|
||||||
|
import 'package:PiliPlus/utils/context_ext.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/utils/image_util.dart';
|
import 'package:PiliPlus/utils/image_util.dart';
|
||||||
|
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@@ -19,8 +21,8 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
this.semanticsLabel,
|
this.semanticsLabel,
|
||||||
this.radius,
|
this.radius,
|
||||||
this.imageBuilder,
|
this.imageBuilder,
|
||||||
this.isLongPic,
|
this.isLongPic = false,
|
||||||
this.callback,
|
this.forceUseCacheWidth = false,
|
||||||
this.getPlaceHolder,
|
this.getPlaceHolder,
|
||||||
this.boxFit,
|
this.boxFit,
|
||||||
});
|
});
|
||||||
@@ -35,30 +37,34 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
final String? semanticsLabel;
|
final String? semanticsLabel;
|
||||||
final double? radius;
|
final double? radius;
|
||||||
final ImageWidgetBuilder? imageBuilder;
|
final ImageWidgetBuilder? imageBuilder;
|
||||||
final Function? isLongPic;
|
final bool isLongPic;
|
||||||
final Function? callback;
|
final bool forceUseCacheWidth;
|
||||||
final Function? getPlaceHolder;
|
final Widget Function()? getPlaceHolder;
|
||||||
final BoxFit? boxFit;
|
final BoxFit? boxFit;
|
||||||
|
|
||||||
|
static Color? reduceLuxColor = Pref.reduceLuxColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final reduce =
|
||||||
|
quality != 100 && reduceLuxColor != null && context.isDarkMode;
|
||||||
return src?.isNotEmpty == true
|
return src?.isNotEmpty == true
|
||||||
? type == ImageType.avatar
|
? type == ImageType.avatar
|
||||||
? ClipOval(child: _buildImage(context))
|
? ClipOval(child: _buildImage(context, reduce))
|
||||||
: radius == 0 || type == ImageType.emote
|
: radius == 0 || type == ImageType.emote
|
||||||
? _buildImage(context)
|
? _buildImage(context, reduce)
|
||||||
: ClipRRect(
|
: ClipRRect(
|
||||||
borderRadius: radius != null
|
borderRadius: radius != null
|
||||||
? BorderRadius.circular(radius!)
|
? BorderRadius.circular(radius!)
|
||||||
: StyleString.mdRadius,
|
: StyleString.mdRadius,
|
||||||
child: _buildImage(context),
|
child: _buildImage(context, reduce),
|
||||||
)
|
)
|
||||||
: getPlaceHolder?.call() ?? placeholder(context);
|
: getPlaceHolder?.call() ?? _placeholder(context, reduce);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildImage(BuildContext context) {
|
Widget _buildImage(BuildContext context, bool reduce) {
|
||||||
int? memCacheWidth, memCacheHeight;
|
int? memCacheWidth, memCacheHeight;
|
||||||
if (height == null || callback?.call() == true || width <= height!) {
|
if (height == null || forceUseCacheWidth || width <= height!) {
|
||||||
memCacheWidth = width.cacheSize(context);
|
memCacheWidth = width.cacheSize(context);
|
||||||
} else {
|
} else {
|
||||||
memCacheHeight = height.cacheSize(context);
|
memCacheHeight = height.cacheSize(context);
|
||||||
@@ -70,20 +76,20 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
memCacheWidth: memCacheWidth,
|
memCacheWidth: memCacheWidth,
|
||||||
memCacheHeight: memCacheHeight,
|
memCacheHeight: memCacheHeight,
|
||||||
fit: boxFit ?? BoxFit.cover,
|
fit: boxFit ?? BoxFit.cover,
|
||||||
alignment: isLongPic?.call() == true
|
alignment: isLongPic ? Alignment.topCenter : Alignment.center,
|
||||||
? Alignment.topCenter
|
|
||||||
: Alignment.center,
|
|
||||||
fadeOutDuration: fadeOutDuration ?? const Duration(milliseconds: 120),
|
fadeOutDuration: fadeOutDuration ?? const Duration(milliseconds: 120),
|
||||||
fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 120),
|
fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 120),
|
||||||
filterQuality: FilterQuality.low,
|
filterQuality: FilterQuality.low,
|
||||||
placeholder: (BuildContext context, String url) =>
|
placeholder: (BuildContext context, String url) =>
|
||||||
getPlaceHolder?.call() ?? placeholder(context),
|
getPlaceHolder?.call() ?? _placeholder(context, reduce),
|
||||||
imageBuilder: imageBuilder,
|
imageBuilder: imageBuilder,
|
||||||
errorWidget: (context, url, error) => placeholder(context),
|
errorWidget: (context, url, error) => _placeholder(context, reduce),
|
||||||
|
colorBlendMode: reduce ? BlendMode.modulate : null,
|
||||||
|
color: reduce ? reduceLuxColor : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget placeholder(BuildContext context) {
|
Widget _placeholder(BuildContext context, bool reduce) {
|
||||||
return Container(
|
return Container(
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@@ -108,6 +114,8 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
cacheWidth: width.cacheSize(context),
|
cacheWidth: width.cacheSize(context),
|
||||||
|
colorBlendMode: reduce ? BlendMode.modulate : null,
|
||||||
|
color: reduce ? reduceLuxColor : null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import 'dart:io';
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:PiliPlus/common/widgets/custom_toast.dart';
|
import 'package:PiliPlus/common/widgets/custom_toast.dart';
|
||||||
|
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
|
||||||
|
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||||
import 'package:PiliPlus/main.dart';
|
import 'package:PiliPlus/main.dart';
|
||||||
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
||||||
@@ -15,6 +17,7 @@ import 'package:PiliPlus/pages/main/controller.dart';
|
|||||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||||
import 'package:PiliPlus/pages/setting/models/model.dart';
|
import 'package:PiliPlus/pages/setting/models/model.dart';
|
||||||
import 'package:PiliPlus/pages/setting/pages/color_select.dart';
|
import 'package:PiliPlus/pages/setting/pages/color_select.dart';
|
||||||
|
import 'package:PiliPlus/pages/setting/slide_color_picker.dart';
|
||||||
import 'package:PiliPlus/pages/setting/widgets/multi_select_dialog.dart';
|
import 'package:PiliPlus/pages/setting/widgets/multi_select_dialog.dart';
|
||||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||||
import 'package:PiliPlus/pages/setting/widgets/slide_dialog.dart';
|
import 'package:PiliPlus/pages/setting/widgets/slide_dialog.dart';
|
||||||
@@ -451,6 +454,67 @@ List<SettingsModel> get styleSettings => [
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SettingsModel(
|
||||||
|
settingsType: SettingsType.normal,
|
||||||
|
onTap: (setState) {
|
||||||
|
showDialog(
|
||||||
|
context: Get.context!,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
title: const Text('Color Picker'),
|
||||||
|
content: SlideColorPicker(
|
||||||
|
showResetBtn: false,
|
||||||
|
color: Pref.reduceLuxColor ?? Colors.white,
|
||||||
|
callback: (Color? color) async {
|
||||||
|
if (color != null && color != Pref.reduceLuxColor) {
|
||||||
|
if (color == Colors.white) {
|
||||||
|
NetworkImgLayer.reduceLuxColor = null;
|
||||||
|
GStorage.setting.delete(SettingBoxKey.reduceLuxColor);
|
||||||
|
SmartDialog.showToast('设置成功');
|
||||||
|
setState();
|
||||||
|
} else {
|
||||||
|
void onConfirm() {
|
||||||
|
NetworkImgLayer.reduceLuxColor = color;
|
||||||
|
GStorage.setting.put(
|
||||||
|
SettingBoxKey.reduceLuxColor,
|
||||||
|
color.toARGB32(),
|
||||||
|
);
|
||||||
|
SmartDialog.showToast('设置成功');
|
||||||
|
setState();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color.computeLuminance() < 0.2) {
|
||||||
|
await showConfirmDialog(
|
||||||
|
context: context,
|
||||||
|
title:
|
||||||
|
'确认使用#${(color.toARGB32() & 0xFFFFFF).toRadixString(16).toUpperCase().padLeft(6)}?',
|
||||||
|
content: '所选颜色过于昏暗,可能会影响图片观看',
|
||||||
|
onConfirm: onConfirm,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
onConfirm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
title: '深色下图片颜色叠加',
|
||||||
|
subtitle: '显示颜色=图片原色x所选颜色,大图查看不受影响',
|
||||||
|
leading: const Icon(Icons.format_color_fill_outlined),
|
||||||
|
getTrailing: () => Container(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Pref.reduceLuxColor ?? Colors.white,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
SettingsModel(
|
SettingsModel(
|
||||||
settingsType: SettingsType.normal,
|
settingsType: SettingsType.normal,
|
||||||
onTap: (setState) async {
|
onTap: (setState) async {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||||
|
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||||
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
||||||
show ReplyInfo;
|
show ReplyInfo;
|
||||||
@@ -50,7 +51,6 @@ import 'package:PiliPlus/utils/page_utils.dart';
|
|||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:PiliPlus/utils/storage_key.dart';
|
import 'package:PiliPlus/utils/storage_key.dart';
|
||||||
import 'package:auto_orientation/auto_orientation.dart';
|
import 'package:auto_orientation/auto_orientation.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:easy_debounce/easy_throttle.dart';
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
||||||
import 'package:floating/floating.dart';
|
import 'package:floating/floating.dart';
|
||||||
@@ -1640,17 +1640,14 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: handlePlay,
|
onTap: handlePlay,
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => CachedNetworkImage(
|
() => NetworkImgLayer(
|
||||||
imageUrl: videoDetailController.cover.value.http2https,
|
src: videoDetailController.cover.value,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
fit: BoxFit.cover,
|
boxFit: BoxFit.cover,
|
||||||
fadeOutDuration: const Duration(milliseconds: 120),
|
fadeOutDuration: const Duration(milliseconds: 120),
|
||||||
fadeInDuration: const Duration(milliseconds: 120),
|
fadeInDuration: const Duration(milliseconds: 120),
|
||||||
memCacheWidth: width.cacheSize(context),
|
forceUseCacheWidth: true,
|
||||||
placeholder: (context, url) => Center(
|
|
||||||
child: Image.asset('assets/images/loading.png'),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -202,7 +202,8 @@ class SettingBoxKey {
|
|||||||
hiddenSettingUnlocked = 'hiddenSettingUnlocked',
|
hiddenSettingUnlocked = 'hiddenSettingUnlocked',
|
||||||
enableGradientBg = 'enableGradientBg',
|
enableGradientBg = 'enableGradientBg',
|
||||||
navBarSort = 'navBarSort',
|
navBarSort = 'navBarSort',
|
||||||
tempPlayerConf = 'tempPlayerConf';
|
tempPlayerConf = 'tempPlayerConf',
|
||||||
|
reduceLuxColor = 'reduceLuxColor';
|
||||||
}
|
}
|
||||||
|
|
||||||
class LocalCacheKey {
|
class LocalCacheKey {
|
||||||
|
|||||||
@@ -779,4 +779,12 @@ class Pref {
|
|||||||
|
|
||||||
static bool get tempPlayerConf =>
|
static bool get tempPlayerConf =>
|
||||||
_setting.get(SettingBoxKey.tempPlayerConf, defaultValue: false);
|
_setting.get(SettingBoxKey.tempPlayerConf, defaultValue: false);
|
||||||
|
|
||||||
|
static Color? get reduceLuxColor {
|
||||||
|
final int? color = _setting.get(SettingBoxKey.reduceLuxColor);
|
||||||
|
if (color != null && color != 0xFFFFFFFF) {
|
||||||
|
return Color(color);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user