2022-11-19 04:32:38 +01:00
|
|
|
import 'dart:ui';
|
|
|
|
|
2024-05-06 09:33:36 +02:00
|
|
|
import 'package:flex_seed_scheme/flex_seed_scheme.dart';
|
2021-04-10 06:28:12 +02:00
|
|
|
import 'package:flutter/material.dart';
|
2023-08-19 18:47:56 +02:00
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import 'package:nc_photos/controller/pref_controller.dart';
|
2024-06-08 21:00:43 +02:00
|
|
|
import 'package:nc_photos/session_storage.dart';
|
2023-08-12 17:24:29 +02:00
|
|
|
import 'package:nc_photos/theme/dimension.dart';
|
2023-08-20 21:04:55 +02:00
|
|
|
import 'package:np_ui/np_ui.dart';
|
2023-07-24 15:06:59 +02:00
|
|
|
|
2023-08-19 18:47:56 +02:00
|
|
|
const defaultSeedColor = Color(0xFF2196F3);
|
2021-04-10 06:28:12 +02:00
|
|
|
|
2024-10-20 16:42:14 +02:00
|
|
|
// Compatibility with flutter 3.22
|
|
|
|
typedef WidgetStateProperty = MaterialStateProperty;
|
|
|
|
typedef WidgetState = MaterialState;
|
|
|
|
|
2022-11-12 10:55:33 +01:00
|
|
|
extension ThemeExtension on ThemeData {
|
|
|
|
double get widthLimitedContentMaxWidth => 550.0;
|
|
|
|
|
|
|
|
Color get listPlaceholderBackgroundColor =>
|
2024-05-16 18:37:33 +02:00
|
|
|
colorScheme.primaryContainer.withOpacity(.6);
|
2022-11-12 10:55:33 +01:00
|
|
|
|
|
|
|
Color get listPlaceholderForegroundColor =>
|
2024-05-16 18:37:33 +02:00
|
|
|
colorScheme.onPrimaryContainer.withOpacity(.7);
|
2022-11-12 10:55:33 +01:00
|
|
|
|
|
|
|
Color get homeNavigationBarBackgroundColor =>
|
2022-11-19 04:32:38 +01:00
|
|
|
elevate(colorScheme.surface, 2).withOpacity(.55);
|
2022-11-12 10:55:33 +01:00
|
|
|
|
|
|
|
Color get onDarkSurface {
|
|
|
|
return brightness == Brightness.light
|
|
|
|
? colorScheme.onInverseSurface
|
|
|
|
: colorScheme.onSurface;
|
|
|
|
}
|
|
|
|
|
2022-11-19 04:32:38 +01:00
|
|
|
ImageFilter get appBarBlurFilter => ImageFilter.blur(
|
|
|
|
sigmaX: 12,
|
|
|
|
sigmaY: 12,
|
|
|
|
tileMode: TileMode.mirror,
|
|
|
|
);
|
|
|
|
|
2022-11-23 17:22:09 +01:00
|
|
|
Color get nextcloudBlue => const Color(0xFF0082C9);
|
|
|
|
|
2024-05-06 09:33:36 +02:00
|
|
|
LinearGradient get photoGridShimmerGradient {
|
|
|
|
final Color color;
|
|
|
|
if (brightness == Brightness.light) {
|
|
|
|
color = Colors.white.withOpacity(.85);
|
|
|
|
} else {
|
|
|
|
color = Colors.white.withOpacity(.25);
|
|
|
|
}
|
|
|
|
return LinearGradient(
|
|
|
|
colors: [
|
|
|
|
listPlaceholderBackgroundColor.withOpacity(0),
|
|
|
|
color,
|
|
|
|
listPlaceholderBackgroundColor.withOpacity(0),
|
|
|
|
],
|
|
|
|
stops: const [0.1, 0.3, 0.4],
|
|
|
|
begin: const Alignment(-1.0, -0.3),
|
|
|
|
end: const Alignment(1.0, 0.3),
|
|
|
|
tileMode: TileMode.clamp,
|
|
|
|
);
|
|
|
|
}
|
2022-11-12 10:55:33 +01:00
|
|
|
}
|
2021-04-10 06:28:12 +02:00
|
|
|
|
2023-06-09 18:41:24 +02:00
|
|
|
class DarkModeSwitchTheme extends StatelessWidget {
|
|
|
|
const DarkModeSwitchTheme({
|
|
|
|
super.key,
|
|
|
|
required this.child,
|
|
|
|
});
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
final theme = Theme.of(context);
|
|
|
|
return Theme(
|
|
|
|
data: theme.copyWith(
|
|
|
|
switchTheme: SwitchThemeData(
|
2024-09-27 15:12:21 +02:00
|
|
|
trackColor: WidgetStateProperty.all(theme.colorScheme.surface),
|
|
|
|
thumbColor: WidgetStateProperty.all(Colors.black87),
|
2023-06-09 18:41:24 +02:00
|
|
|
),
|
|
|
|
colorScheme: theme.colorScheme.copyWith(
|
|
|
|
outline: Colors.transparent,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
child: child,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
final Widget child;
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:47:56 +02:00
|
|
|
ThemeData buildTheme(BuildContext context, Brightness brightness) {
|
2022-11-12 10:55:33 +01:00
|
|
|
return (brightness == Brightness.light)
|
2023-08-19 18:47:56 +02:00
|
|
|
? buildLightTheme(context)
|
|
|
|
: buildDarkTheme(context);
|
2022-11-12 10:55:33 +01:00
|
|
|
}
|
2022-01-15 11:35:15 +01:00
|
|
|
|
2023-08-19 18:47:56 +02:00
|
|
|
ThemeData buildLightTheme(BuildContext context, [ColorScheme? dynamicScheme]) {
|
2024-06-08 21:00:43 +02:00
|
|
|
final colorScheme = _getColorScheme(
|
|
|
|
context,
|
|
|
|
dynamicScheme ?? SessionStorage().lightDynamicColorScheme,
|
|
|
|
Brightness.light,
|
|
|
|
);
|
2023-07-24 15:06:59 +02:00
|
|
|
return _applyColorScheme(colorScheme);
|
2022-11-12 10:55:33 +01:00
|
|
|
}
|
2022-07-12 22:11:27 +02:00
|
|
|
|
2023-08-19 18:47:56 +02:00
|
|
|
ThemeData buildDarkTheme(BuildContext context, [ColorScheme? dynamicScheme]) {
|
2024-06-08 21:00:43 +02:00
|
|
|
final colorScheme = _getColorScheme(
|
|
|
|
context,
|
|
|
|
dynamicScheme ?? SessionStorage().darkDynamicColorScheme,
|
|
|
|
Brightness.dark,
|
|
|
|
);
|
2023-08-19 18:47:56 +02:00
|
|
|
if (context.read<PrefController>().isUseBlackInDarkTheme.value) {
|
2023-07-24 15:06:59 +02:00
|
|
|
return _applyColorScheme(colorScheme.copyWith(
|
|
|
|
background: Colors.black,
|
|
|
|
surface: Colors.grey[900],
|
|
|
|
));
|
2022-11-12 10:55:33 +01:00
|
|
|
} else {
|
2023-07-24 15:06:59 +02:00
|
|
|
return _applyColorScheme(colorScheme);
|
2022-11-12 10:55:33 +01:00
|
|
|
}
|
|
|
|
}
|
2021-04-10 06:28:12 +02:00
|
|
|
|
2023-08-19 18:47:56 +02:00
|
|
|
ColorScheme _getColorScheme(
|
|
|
|
BuildContext context, ColorScheme? dynamicScheme, Brightness brightness) {
|
2024-05-18 16:00:25 +02:00
|
|
|
var primary = context.read<PrefController>().seedColorValue;
|
|
|
|
Color? secondary;
|
|
|
|
if (primary == null) {
|
2023-07-24 15:06:59 +02:00
|
|
|
if (dynamicScheme != null) {
|
|
|
|
return dynamicScheme;
|
|
|
|
} else {
|
2024-05-18 16:00:25 +02:00
|
|
|
primary = defaultSeedColor;
|
2023-07-24 15:06:59 +02:00
|
|
|
}
|
2024-05-18 16:00:25 +02:00
|
|
|
} else {
|
|
|
|
secondary = context.read<PrefController>().secondarySeedColorValue;
|
2023-07-24 15:06:59 +02:00
|
|
|
}
|
2024-04-13 13:45:55 +02:00
|
|
|
return SeedColorScheme.fromSeeds(
|
2023-07-24 15:06:59 +02:00
|
|
|
brightness: brightness,
|
2024-04-13 13:45:55 +02:00
|
|
|
tones: FlexTones.oneHue(brightness),
|
2024-05-18 16:00:25 +02:00
|
|
|
primaryKey: primary,
|
|
|
|
secondaryKey: secondary,
|
2023-07-24 15:06:59 +02:00
|
|
|
);
|
2022-11-12 18:19:28 +01:00
|
|
|
}
|
|
|
|
|
2023-07-24 15:06:59 +02:00
|
|
|
ThemeData _applyColorScheme(ColorScheme colorScheme) {
|
2022-11-12 10:55:33 +01:00
|
|
|
return ThemeData(
|
|
|
|
useMaterial3: true,
|
|
|
|
brightness: colorScheme.brightness,
|
|
|
|
colorScheme: colorScheme,
|
|
|
|
scaffoldBackgroundColor: colorScheme.background,
|
|
|
|
appBarTheme: AppBarTheme(
|
|
|
|
backgroundColor: colorScheme.background,
|
|
|
|
foregroundColor: colorScheme.onSurface,
|
|
|
|
),
|
|
|
|
listTileTheme: ListTileThemeData(
|
|
|
|
iconColor: colorScheme.onSurfaceVariant,
|
|
|
|
),
|
|
|
|
iconTheme: IconThemeData(
|
|
|
|
color: colorScheme.onSurfaceVariant,
|
|
|
|
),
|
|
|
|
// remove after dialog supports m3
|
|
|
|
dialogBackgroundColor:
|
|
|
|
Color.lerp(colorScheme.surface, colorScheme.surfaceTint, 0.11),
|
|
|
|
popupMenuTheme: PopupMenuThemeData(
|
|
|
|
// remove after menu supports m3
|
|
|
|
color: Color.lerp(colorScheme.surface, colorScheme.surfaceTint, 0.08),
|
|
|
|
),
|
|
|
|
navigationBarTheme: const NavigationBarThemeData(
|
|
|
|
// default for Material 3
|
|
|
|
height: 80,
|
|
|
|
),
|
|
|
|
// remove after checkbox supports m3
|
|
|
|
// see: https://m3.material.io/components/checkbox/specs
|
|
|
|
checkboxTheme: CheckboxThemeData(
|
2024-09-27 15:12:21 +02:00
|
|
|
fillColor: WidgetStateProperty.resolveWith((states) {
|
|
|
|
if (states.contains(WidgetState.disabled)) {
|
2024-06-01 14:42:45 +02:00
|
|
|
return Colors.transparent;
|
2022-11-12 10:55:33 +01:00
|
|
|
} else {
|
2024-09-27 15:12:21 +02:00
|
|
|
if (states.contains(WidgetState.selected)) {
|
2024-05-16 18:37:33 +02:00
|
|
|
return colorScheme.secondary;
|
2022-11-12 10:55:33 +01:00
|
|
|
} else {
|
2024-06-01 14:42:45 +02:00
|
|
|
return Colors.transparent;
|
2022-11-12 10:55:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
2024-09-27 15:12:21 +02:00
|
|
|
checkColor: WidgetStateProperty.all(colorScheme.onPrimary),
|
2022-11-12 10:55:33 +01:00
|
|
|
),
|
|
|
|
// remove after checkbox supports m3
|
|
|
|
// see: https://m3.material.io/components/switch/specs
|
|
|
|
// the color here is slightly modified to work better with the M2 switch
|
|
|
|
switchTheme: SwitchThemeData(
|
2024-09-27 15:12:21 +02:00
|
|
|
trackColor: WidgetStateProperty.resolveWith((states) {
|
|
|
|
if (states.contains(WidgetState.disabled)) {
|
|
|
|
if (states.contains(WidgetState.selected)) {
|
2022-11-12 10:55:33 +01:00
|
|
|
return colorScheme.onSurface.withOpacity(.12);
|
|
|
|
} else {
|
|
|
|
return colorScheme.surfaceVariant.withOpacity(.12);
|
|
|
|
}
|
|
|
|
} else {
|
2024-09-27 15:12:21 +02:00
|
|
|
if (states.contains(WidgetState.selected)) {
|
2022-11-12 10:55:33 +01:00
|
|
|
// return colorScheme.primary;
|
2024-05-16 18:37:33 +02:00
|
|
|
return colorScheme.secondary;
|
2022-11-12 10:55:33 +01:00
|
|
|
} else {
|
|
|
|
return colorScheme.surfaceVariant;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
2024-09-27 15:12:21 +02:00
|
|
|
thumbColor: WidgetStateProperty.resolveWith((states) {
|
|
|
|
if (states.contains(WidgetState.disabled)) {
|
|
|
|
if (states.contains(WidgetState.selected)) {
|
2022-11-12 10:55:33 +01:00
|
|
|
// return colorScheme.surface;
|
|
|
|
return colorScheme.onSurface.withOpacity(.38);
|
|
|
|
} else {
|
|
|
|
return colorScheme.onSurface.withOpacity(.38);
|
|
|
|
}
|
|
|
|
} else {
|
2024-09-27 15:12:21 +02:00
|
|
|
if (states.contains(WidgetState.selected)) {
|
2022-11-12 10:55:33 +01:00
|
|
|
// return colorScheme.onPrimary;
|
2024-05-16 18:37:33 +02:00
|
|
|
return colorScheme.onSecondary;
|
2022-11-12 10:55:33 +01:00
|
|
|
} else {
|
|
|
|
return colorScheme.outline;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
snackBarTheme: SnackBarThemeData(
|
|
|
|
backgroundColor: colorScheme.inverseSurface,
|
|
|
|
contentTextStyle: TextStyle(
|
|
|
|
color: colorScheme.onInverseSurface,
|
|
|
|
),
|
|
|
|
actionTextColor: colorScheme.inversePrimary,
|
2023-03-19 10:02:42 +01:00
|
|
|
behavior: SnackBarBehavior.floating,
|
2022-11-12 10:55:33 +01:00
|
|
|
),
|
2024-05-16 18:37:33 +02:00
|
|
|
sliderTheme: SliderThemeData(
|
|
|
|
activeTrackColor: colorScheme.secondary,
|
|
|
|
inactiveTrackColor: colorScheme.secondaryContainer,
|
|
|
|
thumbColor: colorScheme.secondary,
|
|
|
|
),
|
|
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
|
|
style: ButtonStyle(
|
|
|
|
backgroundColor:
|
2024-09-27 15:12:21 +02:00
|
|
|
WidgetStateProperty.all(colorScheme.secondaryContainer),
|
|
|
|
foregroundColor: WidgetStateProperty.all(colorScheme.secondary),
|
2024-05-16 18:37:33 +02:00
|
|
|
overlayColor:
|
2024-09-27 15:12:21 +02:00
|
|
|
WidgetStateProperty.all(colorScheme.secondary.withOpacity(.1)),
|
2024-05-16 18:37:33 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
textButtonTheme: TextButtonThemeData(
|
|
|
|
style: ButtonStyle(
|
2024-09-27 15:12:21 +02:00
|
|
|
foregroundColor: WidgetStateProperty.all(colorScheme.secondary),
|
2024-05-16 18:37:33 +02:00
|
|
|
overlayColor:
|
2024-09-27 15:12:21 +02:00
|
|
|
WidgetStateProperty.all(colorScheme.secondary.withOpacity(.1)),
|
2024-05-16 18:37:33 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
textSelectionTheme: TextSelectionThemeData(
|
|
|
|
cursorColor: colorScheme.secondary,
|
|
|
|
selectionHandleColor: colorScheme.secondary,
|
|
|
|
selectionColor: colorScheme.secondary.withOpacity(.4),
|
|
|
|
),
|
|
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
|
|
focusedBorder: UnderlineInputBorder(
|
|
|
|
borderSide: BorderSide(color: colorScheme.secondary, width: 2),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
chipTheme: ChipThemeData(
|
|
|
|
selectedColor: Color.lerp(
|
|
|
|
colorScheme.secondaryContainer, colorScheme.surfaceTint, .14),
|
|
|
|
iconTheme: IconThemeData(
|
|
|
|
color: colorScheme.secondary,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
progressIndicatorTheme:
|
|
|
|
ProgressIndicatorThemeData(color: colorScheme.secondary),
|
2022-11-12 10:55:33 +01:00
|
|
|
extensions: [
|
|
|
|
M3(
|
|
|
|
checkbox: M3Checkbox(
|
|
|
|
disabled: M3CheckboxDisabled(
|
|
|
|
container: colorScheme.onSurface.withOpacity(.38),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
filterChip: M3FilterChip(
|
|
|
|
disabled: M3FilterChipDisabled(
|
|
|
|
containerSelected: colorScheme.onSurface.withOpacity(.12),
|
|
|
|
labelText: colorScheme.onSurface.withOpacity(.38),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
listTile: M3ListTile(
|
|
|
|
enabled: M3ListTileEnabled(
|
|
|
|
headline: colorScheme.onSurface,
|
|
|
|
supportingText: colorScheme.onSurfaceVariant,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2023-08-12 17:24:29 +02:00
|
|
|
const AppDimension(
|
|
|
|
homeBottomAppBarHeight: 68,
|
|
|
|
),
|
2022-11-12 10:55:33 +01:00
|
|
|
],
|
|
|
|
);
|
2021-10-18 13:34:25 +02:00
|
|
|
}
|
2023-08-04 21:47:09 +02:00
|
|
|
|
|
|
|
extension BrightnessExtension on Brightness {
|
|
|
|
Brightness invert() {
|
|
|
|
switch (this) {
|
|
|
|
case Brightness.dark:
|
|
|
|
return Brightness.light;
|
|
|
|
case Brightness.light:
|
|
|
|
return Brightness.dark;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|