nc-photos/app/lib/theme.dart

331 lines
9.9 KiB
Dart
Raw Normal View History

2022-11-19 04:32:38 +01:00
import 'dart:ui';
import 'package:flex_seed_scheme/flex_seed_scheme.dart';
2021-04-10 06:28:12 +02:00
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:nc_photos/controller/pref_controller.dart';
import 'package:nc_photos/session_storage.dart';
2023-08-12 17:24:29 +02:00
import 'package:nc_photos/theme/dimension.dart';
import 'package:np_ui/np_ui.dart';
const defaultSeedColor = Color(0xFF2196F3);
2021-04-10 06:28:12 +02:00
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);
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
/// Apply surface tint to [color] based on the [elevation] level
///
/// This function is a temporary workaround for widgets not yet fully
/// supported Material 3
Color elevate(Color color, int elevation) {
final double tintOpacity;
switch (elevation) {
case 1:
tintOpacity = 0.05;
break;
case 2:
tintOpacity = 0.08;
break;
case 3:
tintOpacity = 0.11;
break;
case 4:
tintOpacity = 0.12;
break;
case 5:
default:
tintOpacity = 0.14;
break;
2021-04-10 06:28:12 +02:00
}
2022-11-12 10:55:33 +01:00
return Color.lerp(color, colorScheme.surfaceTint, tintOpacity)!;
2021-04-10 06:28:12 +02:00
}
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(
trackColor: MaterialStateProperty.all(theme.colorScheme.surface),
thumbColor: MaterialStateProperty.all(Colors.black87),
),
colorScheme: theme.colorScheme.copyWith(
outline: Colors.transparent,
),
),
child: child,
);
}
final Widget child;
}
ThemeData buildTheme(BuildContext context, Brightness brightness) {
2022-11-12 10:55:33 +01:00
return (brightness == Brightness.light)
? buildLightTheme(context)
: buildDarkTheme(context);
2022-11-12 10:55:33 +01:00
}
2022-01-15 11:35:15 +01:00
ThemeData buildLightTheme(BuildContext context, [ColorScheme? dynamicScheme]) {
final colorScheme = _getColorScheme(
context,
dynamicScheme ?? SessionStorage().lightDynamicColorScheme,
Brightness.light,
);
return _applyColorScheme(colorScheme);
2022-11-12 10:55:33 +01:00
}
2022-07-12 22:11:27 +02:00
ThemeData buildDarkTheme(BuildContext context, [ColorScheme? dynamicScheme]) {
final colorScheme = _getColorScheme(
context,
dynamicScheme ?? SessionStorage().darkDynamicColorScheme,
Brightness.dark,
);
if (context.read<PrefController>().isUseBlackInDarkTheme.value) {
return _applyColorScheme(colorScheme.copyWith(
background: Colors.black,
surface: Colors.grey[900],
));
2022-11-12 10:55:33 +01:00
} else {
return _applyColorScheme(colorScheme);
2022-11-12 10:55:33 +01:00
}
}
2021-04-10 06:28:12 +02:00
ColorScheme _getColorScheme(
BuildContext context, ColorScheme? dynamicScheme, Brightness brightness) {
var primary = context.read<PrefController>().seedColorValue;
Color? secondary;
if (primary == null) {
if (dynamicScheme != null) {
return dynamicScheme;
} else {
primary = defaultSeedColor;
}
} else {
secondary = context.read<PrefController>().secondarySeedColorValue;
}
2024-04-13 13:45:55 +02:00
return SeedColorScheme.fromSeeds(
brightness: brightness,
2024-04-13 13:45:55 +02:00
tones: FlexTones.oneHue(brightness),
primaryKey: primary,
secondaryKey: secondary,
);
}
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(
fillColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
2024-06-01 14:42:45 +02:00
return Colors.transparent;
2022-11-12 10:55:33 +01:00
} else {
if (states.contains(MaterialState.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
}
}
}),
checkColor: MaterialStateProperty.all(colorScheme.onPrimary),
),
// 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(
trackColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return colorScheme.onSurface.withOpacity(.12);
} else {
return colorScheme.surfaceVariant.withOpacity(.12);
}
} else {
if (states.contains(MaterialState.selected)) {
// 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;
}
}
}),
thumbColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
// return colorScheme.surface;
return colorScheme.onSurface.withOpacity(.38);
} else {
return colorScheme.onSurface.withOpacity(.38);
}
} else {
if (states.contains(MaterialState.selected)) {
// 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,
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:
MaterialStateProperty.all(colorScheme.secondaryContainer),
foregroundColor: MaterialStateProperty.all(colorScheme.secondary),
overlayColor:
MaterialStateProperty.all(colorScheme.secondary.withOpacity(.1)),
),
),
textButtonTheme: TextButtonThemeData(
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all(colorScheme.secondary),
overlayColor:
MaterialStateProperty.all(colorScheme.secondary.withOpacity(.1)),
),
),
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;
}
}
}