Material 3 theme

This commit is contained in:
Ming Ming 2022-11-12 17:55:33 +08:00
parent 9682f81f39
commit 93d966ad08
63 changed files with 1588 additions and 1810 deletions

View file

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
const lightColorScheme = ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF0061A4),
onPrimary: Color(0xFFFFFFFF),
primaryContainer: Color(0xFFD1E4FF),
onPrimaryContainer: Color(0xFF001D36),
secondary: Color(0xFF535F70),
onSecondary: Color(0xFFFFFFFF),
secondaryContainer: Color(0xFFD7E3F7),
onSecondaryContainer: Color(0xFF101C2B),
tertiary: Color(0xFF6B5778),
onTertiary: Color(0xFFFFFFFF),
tertiaryContainer: Color(0xFFF2DAFF),
onTertiaryContainer: Color(0xFF251431),
error: Color(0xFFBA1A1A),
errorContainer: Color(0xFFFFDAD6),
onError: Color(0xFFFFFFFF),
onErrorContainer: Color(0xFF410002),
background: Color(0xFFFDFCFF),
onBackground: Color(0xFF1A1C1E),
surface: Color(0xFFFDFCFF),
onSurface: Color(0xFF1A1C1E),
surfaceVariant: Color(0xFFDFE2EB),
onSurfaceVariant: Color(0xFF43474E),
outline: Color(0xFF73777F),
onInverseSurface: Color(0xFFF1F0F4),
inverseSurface: Color(0xFF2F3033),
inversePrimary: Color(0xFF9ECAFF),
shadow: Color(0xFF000000),
surfaceTint: Color(0xFF0061A4),
// outlineVariant: Color(0xFFC3C7CF),
// scrim: Color(0xFF000000),
);
const darkColorScheme = ColorScheme(
brightness: Brightness.dark,
primary: Color(0xFF9ECAFF),
onPrimary: Color(0xFF003258),
primaryContainer: Color(0xFF00497D),
onPrimaryContainer: Color(0xFFD1E4FF),
secondary: Color(0xFFBBC7DB),
onSecondary: Color(0xFF253140),
secondaryContainer: Color(0xFF3B4858),
onSecondaryContainer: Color(0xFFD7E3F7),
tertiary: Color(0xFFD6BEE4),
onTertiary: Color(0xFF3B2948),
tertiaryContainer: Color(0xFF523F5F),
onTertiaryContainer: Color(0xFFF2DAFF),
error: Color(0xFFFFB4AB),
errorContainer: Color(0xFF93000A),
onError: Color(0xFF690005),
onErrorContainer: Color(0xFFFFDAD6),
background: Color(0xFF1A1C1E),
onBackground: Color(0xFFE2E2E6),
surface: Color(0xFF1A1C1E),
onSurface: Color(0xFFE2E2E6),
surfaceVariant: Color(0xFF43474E),
onSurfaceVariant: Color(0xFFC3C7CF),
outline: Color(0xFF8D9199),
onInverseSurface: Color(0xFF1A1C1E),
inverseSurface: Color(0xFFE2E2E6),
inversePrimary: Color(0xFF0061A4),
shadow: Color(0xFF000000),
surfaceTint: Color(0xFF9ECAFF),
// outlineVariant: Color(0xFF43474E),
// scrim: Color(0xFF000000),
);

148
app/lib/material3.dart Normal file
View file

@ -0,0 +1,148 @@
import 'package:flutter/material.dart';
class M3 extends ThemeExtension<M3> {
const M3({
required this.checkbox,
required this.filterChip,
required this.listTile,
});
static M3 of(BuildContext context) => Theme.of(context).extension<M3>()!;
@override
M3 copyWith({
M3Checkbox? checkbox,
M3FilterChip? filterChip,
M3ListTile? listTile,
}) =>
M3(
checkbox: checkbox ?? this.checkbox,
filterChip: filterChip ?? this.filterChip,
listTile: listTile ?? this.listTile,
);
@override
M3 lerp(ThemeExtension<M3>? other, double t) {
if (other is! M3) {
return this;
}
return M3(
checkbox: checkbox.lerp(other.checkbox, t),
filterChip: filterChip.lerp(other.filterChip, t),
listTile: listTile.lerp(other.listTile, t),
);
}
final M3Checkbox checkbox;
final M3FilterChip filterChip;
final M3ListTile listTile;
}
class M3Checkbox {
const M3Checkbox({
required this.disabled,
});
M3Checkbox lerp(M3Checkbox? other, double t) {
if (other is! M3Checkbox) {
return this;
}
return M3Checkbox(
disabled: disabled.lerp(other.disabled, t),
);
}
final M3CheckboxDisabled disabled;
}
class M3CheckboxDisabled {
const M3CheckboxDisabled({
required this.container,
});
M3CheckboxDisabled lerp(M3CheckboxDisabled? other, double t) {
if (other is! M3CheckboxDisabled) {
return this;
}
return M3CheckboxDisabled(
container: Color.lerp(container, other.container, t)!,
);
}
final Color container;
}
class M3FilterChip {
const M3FilterChip({
required this.disabled,
});
M3FilterChip lerp(M3FilterChip? other, double t) {
if (other is! M3FilterChip) {
return this;
}
return M3FilterChip(
disabled: disabled.lerp(other.disabled, t),
);
}
final M3FilterChipDisabled disabled;
}
class M3FilterChipDisabled {
const M3FilterChipDisabled({
required this.containerSelected,
required this.labelText,
});
M3FilterChipDisabled lerp(M3FilterChipDisabled? other, double t) {
if (other is! M3FilterChipDisabled) {
return this;
}
return M3FilterChipDisabled(
containerSelected:
Color.lerp(containerSelected, other.containerSelected, t)!,
labelText: Color.lerp(labelText, other.labelText, t)!,
);
}
final Color containerSelected;
final Color labelText;
}
class M3ListTile {
const M3ListTile({
required this.enabled,
});
M3ListTile lerp(M3ListTile? other, double t) {
if (other is! M3ListTile) {
return this;
}
return M3ListTile(
enabled: enabled.lerp(other.enabled, t),
);
}
final M3ListTileEnabled enabled;
}
class M3ListTileEnabled {
const M3ListTileEnabled({
required this.headline,
required this.supportingText,
});
M3ListTileEnabled lerp(M3ListTileEnabled? other, double t) {
if (other is! M3ListTileEnabled) {
return this;
}
return M3ListTileEnabled(
headline: Color.lerp(headline, other.headline, t)!,
supportingText: Color.lerp(supportingText, other.supportingText, t)!,
);
}
final Color headline;
final Color supportingText;
}

View file

@ -1,213 +1,196 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/color_schemes.g.dart';
import 'package:nc_photos/material3.dart';
import 'package:nc_photos/pref.dart';
class AppTheme extends StatelessWidget {
const AppTheme({
Key? key,
required this.child,
this.brightnessOverride,
}) : super(key: key);
extension ThemeExtension on ThemeData {
double get widthLimitedContentMaxWidth => 550.0;
factory AppTheme.light({
Key? key,
required Widget child,
}) =>
AppTheme(
key: key,
brightnessOverride: Brightness.light,
child: child,
);
Color get listPlaceholderBackgroundColor =>
colorScheme.secondaryContainer.withOpacity(.6);
factory AppTheme.dark({
Key? key,
required Widget child,
}) =>
AppTheme(
key: key,
brightnessOverride: Brightness.dark,
child: child,
);
Color get listPlaceholderForegroundColor =>
colorScheme.onSecondaryContainer.withOpacity(.7);
@override
Widget build(BuildContext context) {
return Theme(
data: _buildThemeData(context),
child: DefaultTextStyle(
style: _buildTextStyle(context),
child: child,
),
);
Color get homeNavigationBarBackgroundColor =>
elevate(colorScheme.surface, 2).withOpacity(.77);
Color get onDarkSurface {
return brightness == Brightness.light
? colorScheme.onInverseSurface
: colorScheme.onSurface;
}
static ThemeData buildThemeData(BuildContext context) {
final theme = Theme.of(context);
return theme.brightness == Brightness.light
? buildLightThemeData()
: buildDarkThemeData();
}
static AppBarTheme getContextualAppBarTheme(BuildContext context) {
final theme = Theme.of(context);
if (theme.brightness == Brightness.light) {
return theme.appBarTheme.copyWith(
backgroundColor: Colors.grey[800],
foregroundColor: Colors.white.withOpacity(.87),
);
} else {
return theme.appBarTheme.copyWith(
backgroundColor: Colors.grey[200],
foregroundColor: Colors.black87,
);
/// 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;
}
return Color.lerp(color, colorScheme.surfaceTint, tintOpacity)!;
}
}
static Color getSelectionOverlayColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.light
? primarySwatchLight[100]!.withOpacity(0.7)
: primarySwatchDark[700]!.withOpacity(0.7);
ThemeData buildTheme(Brightness brightness) {
return (brightness == Brightness.light)
? buildLightTheme()
: buildDarkTheme();
}
ThemeData buildLightTheme() {
final theme = _applyColorScheme(lightColorScheme);
return theme;
}
ThemeData buildDarkTheme() {
final ThemeData theme;
if (Pref().isUseBlackInDarkThemeOr(false)) {
theme = _applyColorScheme(darkColorScheme.copyWith(
background: Colors.black,
surface: Colors.grey[900],
));
} else {
theme = _applyColorScheme(darkColorScheme);
}
return theme;
}
static Color getOverscrollIndicatorColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.light
? Colors.grey[800]!
: Colors.grey[200]!;
}
static Color getRootPickerContentBoxColor(BuildContext context) {
return Colors.blue[200]!;
}
static Color getPrimaryTextColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.light
? primaryTextColorLight
: primaryTextColorDark;
}
static Color getSecondaryTextColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.6)
: Colors.white60;
}
static Color getPrimaryTextColorInverse(BuildContext context) =>
Theme.of(context).brightness == Brightness.light
? primaryTextColorDark
: primaryTextColorLight;
static Color getAppBarDarkModeSwitchColor(BuildContext context) {
return Colors.black87;
}
static Color getAppBarDarkModeSwitchTrackColor(BuildContext context) {
return Colors.white.withOpacity(.5);
}
static Color getListItemBackgroundColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.light
? Colors.black26
: Colors.white12;
}
static Color getUnfocusedIconColor(BuildContext context) {
return Theme.of(context).brightness == Brightness.light
? unfocusedIconColorLight
: unfocusedIconColorDark;
}
static ThemeData buildLightThemeData() {
final theme = ThemeData(
brightness: Brightness.light,
primarySwatch: AppTheme.primarySwatchLight,
);
final appBarTheme = theme.appBarTheme.copyWith(
backgroundColor: theme.scaffoldBackgroundColor,
foregroundColor: theme.colorScheme.onSurface,
);
return theme.copyWith(appBarTheme: appBarTheme);
}
static ThemeData buildDarkThemeData() {
final Color background;
final Color popup;
if (Pref().isUseBlackInDarkThemeOr(false)) {
background = Colors.black;
popup = Colors.grey[900]!;
} else {
// in the material spec, black is suggested to be 0x121212, but the one
// used in flutter by default is 0x303030, why?
background = Colors.grey[850]!;
popup = Colors.grey[800]!;
}
final theme = ThemeData(
brightness: Brightness.dark,
primarySwatch: AppTheme.primarySwatchDark,
scaffoldBackgroundColor: background,
dialogBackgroundColor: popup,
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: background,
),
popupMenuTheme: PopupMenuThemeData(
color: popup,
),
checkboxTheme: CheckboxThemeData(
fillColor: _CheckboxDarkColorProperty(),
),
);
final appBarTheme = theme.appBarTheme.copyWith(
backgroundColor: background,
foregroundColor: theme.colorScheme.onSurface,
);
return theme.copyWith(appBarTheme: appBarTheme);
}
ThemeData _buildThemeData(BuildContext context) {
return (brightnessOverride ?? Theme.of(context).brightness) ==
Brightness.light
? buildLightThemeData()
: buildDarkThemeData();
}
TextStyle _buildTextStyle(BuildContext context) {
return (brightnessOverride ?? Theme.of(context).brightness) ==
Brightness.light
? const TextStyle(color: AppTheme.primaryTextColorLight)
: TextStyle(color: AppTheme.primaryTextColorDark);
}
static const primarySwatchLight = Colors.blue;
static const primarySwatchDark = Colors.cyan;
static const primaryTextColorLight = Colors.black87;
static final primaryTextColorDark = Colors.white.withOpacity(.87);
static const unfocusedIconColorLight = Colors.black54;
static const unfocusedIconColorDark = Colors.white70;
static const widthLimitedContentMaxWidth = 550.0;
/// Make a TextButton look like a default FlatButton. See
/// https://flutter.dev/go/material-button-migration-guide
static final flatButtonStyle = TextButton.styleFrom(
primary: Colors.black87,
minimumSize: const Size(88, 36),
padding: const EdgeInsets.symmetric(horizontal: 16.0),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)),
ThemeData buildDarkModeSwitchTheme(BuildContext context) {
final theme = Theme.of(context);
return theme.copyWith(
switchTheme: SwitchThemeData(
trackColor: MaterialStateProperty.all(theme.colorScheme.surfaceVariant),
thumbColor: MaterialStateProperty.all(Colors.black87),
),
);
final Widget child;
final Brightness? brightnessOverride;
}
class _CheckboxDarkColorProperty implements MaterialStateProperty<Color?> {
@override
resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return Colors.cyanAccent[400];
} else {
return null;
}
}
ThemeData _applyColorScheme(ColorScheme colorScheme) {
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)) {
return colorScheme.onSurface;
} else {
if (states.contains(MaterialState.selected)) {
return colorScheme.primary;
} else {
return Colors.transparent;
}
}
}),
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;
return colorScheme.primaryContainer;
} 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;
return colorScheme.primary;
} else {
return colorScheme.outline;
}
}
}),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: colorScheme.inverseSurface,
contentTextStyle: TextStyle(
color: colorScheme.onInverseSurface,
),
actionTextColor: colorScheme.inversePrimary,
),
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,
),
),
),
],
);
}

View file

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/theme.dart';
class AboutGeocodingDialog extends StatelessWidget {
const AboutGeocodingDialog({
@ -9,21 +8,19 @@ class AboutGeocodingDialog extends StatelessWidget {
@override
build(BuildContext context) {
return AppTheme(
child: AlertDialog(
title: Text(L10n.global().gpsPlaceAboutDialogTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(L10n.global().gpsPlaceAboutDialogContent),
const SizedBox(height: 16),
const Divider(height: 16),
const Text(
"Based on GeoNames Gazetteer data by GeoNames, licensed under CC BY 4.0",
),
],
),
return AlertDialog(
title: Text(L10n.global().gpsPlaceAboutDialogTitle),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(L10n.global().gpsPlaceAboutDialogContent),
const SizedBox(height: 16),
const Divider(height: 16),
const Text(
"Based on GeoNames Gazetteer data by GeoNames, licensed under CC BY 4.0",
),
],
),
);
}

View file

@ -11,7 +11,6 @@ import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/home.dart';
import 'package:nc_photos/widget/settings.dart';
import 'package:nc_photos/widget/sign_in.dart';
@ -49,10 +48,7 @@ class _AccountPickerDialogState extends State<AccountPickerDialog> {
title: Text(label ?? a.url),
subtitle: label == null ? Text(a.username2) : null,
trailing: IconButton(
icon: Icon(
Icons.close,
color: AppTheme.getUnfocusedIconColor(context),
),
icon: const Icon(Icons.close),
tooltip: L10n.global().deleteTooltip,
onPressed: () => _onRemoveItemPressed(a),
),
@ -69,43 +65,35 @@ class _AccountPickerDialogState extends State<AccountPickerDialog> {
},
child: Tooltip(
message: L10n.global().addServerTooltip,
child: Center(
child: Icon(
Icons.add,
color: AppTheme.getSecondaryTextColor(context),
),
child: const Center(
child: Icon(Icons.add),
),
),
),
];
final accountLabel = AccountPref.of(widget.account).getAccountLabel();
return AppTheme(
child: SimpleDialog(
title: ListTile(
dense: true,
title: Text(
accountLabel ?? widget.account.url,
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: accountLabel == null
? Text(
widget.account.username2,
style: const TextStyle(fontWeight: FontWeight.bold),
)
: null,
trailing: IconButton(
icon: Icon(
Icons.settings_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
tooltip: L10n.global().settingsMenuLabel,
onPressed: _onEditPressed,
),
return SimpleDialog(
title: ListTile(
dense: true,
title: Text(
accountLabel ?? widget.account.url,
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: accountLabel == null
? Text(
widget.account.username2,
style: const TextStyle(fontWeight: FontWeight.bold),
)
: null,
trailing: IconButton(
icon: const Icon(Icons.settings_outlined),
tooltip: L10n.global().settingsMenuLabel,
onPressed: _onEditPressed,
),
titlePadding: const EdgeInsetsDirectional.fromSTEB(8, 16, 8, 0),
contentPadding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 8),
children: otherAccountOptions + addAccountOptions,
),
titlePadding: const EdgeInsetsDirectional.fromSTEB(8, 16, 8, 0),
contentPadding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 8),
children: otherAccountOptions + addAccountOptions,
);
}

View file

@ -26,7 +26,6 @@ import 'package:nc_photos/pref.dart';
import 'package:nc_photos/session_storage.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/ls_single_file.dart';
import 'package:nc_photos/use_case/preprocess_album.dart';
import 'package:nc_photos/use_case/remove_from_album.dart';
@ -111,20 +110,18 @@ class _AlbumBrowserState extends State<AlbumBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) {
if (isEditMode) {
return Form(
key: _editFormKey,
child: _buildContent(context),
);
} else {
return _buildContent(context);
}
},
),
return Scaffold(
body: Builder(
builder: (context) {
if (isEditMode) {
return Form(
key: _editFormKey,
child: _buildContent(context),
);
} else {
return _buildContent(context);
}
},
),
);
}
@ -253,17 +250,7 @@ class _AlbumBrowserState extends State<AlbumBrowser>
child: content,
);
}
return buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: content,
),
);
return buildItemStreamListOuter(context, child: content);
}
Widget _buildAppBar(BuildContext context) {

View file

@ -6,7 +6,6 @@ import 'package:nc_photos/api/api.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/cache_manager_util.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/theme.dart';
class AlbumBrowserAppBar extends StatelessWidget {
const AlbumBrowserAppBar({
@ -26,9 +25,8 @@ class AlbumBrowserAppBar extends StatelessWidget {
background: _getAppBarCover(context, account, coverPreviewUrl),
title: Text(
album.name,
style: TextStyle(
color: AppTheme.getPrimaryTextColor(context),
),
style:
TextStyle(color: Theme.of(context).appBarTheme.foregroundColor),
),
),
actions: actions,
@ -95,9 +93,9 @@ class _AlbumBrowserEditAppBarState extends State<AlbumBrowserEditAppBar> {
onSaved: (_) {
widget.onAlbumNameSaved?.call(_controller.text);
},
style: TextStyle(
color: AppTheme.getPrimaryTextColor(context),
),
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
),
leading: IconButton(

View file

@ -8,7 +8,6 @@ import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/dir_picker.dart';
class AlbumDirPickerArguments {
@ -45,10 +44,8 @@ class AlbumDirPicker extends StatefulWidget {
class _AlbumDirPickerState extends State<AlbumDirPicker> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: _buildContent(context),
),
return Scaffold(
body: _buildContent(context),
);
}

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/theme.dart';
class AlbumGridItem extends StatelessWidget {
const AlbumGridItem({
@ -40,23 +39,18 @@ class AlbumGridItem extends StatelessWidget {
const SizedBox(height: 8),
Text(
title,
style: Theme.of(context).textTheme.bodyText1!.copyWith(
color: AppTheme.getPrimaryTextColor(context),
),
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.start,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
const SizedBox(height: 2),
Row(
children: [
Expanded(
child: Text(
subtitle ?? "",
style: Theme.of(context).textTheme.bodyText2!.copyWith(
fontSize: 10,
color: AppTheme.getSecondaryTextColor(context),
),
style: Theme.of(context).textTheme.bodySmall,
textAlign: TextAlign.start,
maxLines: 1,
overflow: TextOverflow.ellipsis,
@ -65,10 +59,7 @@ class AlbumGridItem extends StatelessWidget {
if (subtitle2?.isNotEmpty == true)
Text(
subtitle2!,
style: Theme.of(context).textTheme.bodyText2!.copyWith(
fontSize: 10,
color: AppTheme.getSecondaryTextColor(context),
),
style: Theme.of(context).textTheme.bodySmall,
textAlign: TextAlign.end,
maxLines: 1,
),

View file

@ -20,7 +20,6 @@ import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/create_album.dart';
import 'package:nc_photos/use_case/preprocess_album.dart';
import 'package:nc_photos/use_case/update_album_with_actual_items.dart';
@ -74,17 +73,14 @@ class _AlbumImporterState extends State<AlbumImporter> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body:
BlocListener<ListImportableAlbumBloc, ListImportableAlbumBlocState>(
return Scaffold(
body: BlocListener<ListImportableAlbumBloc, ListImportableAlbumBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child:
BlocBuilder<ListImportableAlbumBloc, ListImportableAlbumBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListImportableAlbumBloc,
ListImportableAlbumBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);

View file

@ -59,15 +59,13 @@ class _AlbumPickerState extends State<AlbumPicker>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListAlbumBloc, ListAlbumBlocState>(
return Scaffold(
body: BlocListener<ListAlbumBloc, ListAlbumBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListAlbumBloc, ListAlbumBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListAlbumBloc, ListAlbumBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -125,11 +123,11 @@ class _AlbumPickerState extends State<AlbumPicker>
cover: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Container(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
constraints: const BoxConstraints.expand(),
child: Icon(
Icons.add,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
size: 88,
),
),

View file

@ -22,7 +22,6 @@ import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/string_extension.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/create_share.dart';
import 'package:nc_photos/use_case/remove_share.dart';
import 'package:nc_photos/widget/empty_list_indicator.dart';
@ -73,17 +72,15 @@ class _AlbumShareOutlierBrowserState extends State<AlbumShareOutlierBrowser> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListAlbumShareOutlierBloc,
return Scaffold(
body: BlocListener<ListAlbumShareOutlierBloc,
ListAlbumShareOutlierBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListAlbumShareOutlierBloc,
ListAlbumShareOutlierBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListAlbumShareOutlierBloc,
ListAlbumShareOutlierBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -112,23 +109,16 @@ class _AlbumShareOutlierBrowserState extends State<AlbumShareOutlierBrowser> {
} else {
return Stack(
children: [
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => _buildItem(context, _items[index]),
childCount: _items.length,
),
CustomScrollView(
slivers: [
_buildAppBar(context),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => _buildItem(context, _items[index]),
childCount: _items.length,
),
],
),
),
],
),
if (state is ListAlbumShareOutlierBlocLoading)
const Align(
@ -264,20 +254,11 @@ class _AlbumShareOutlierBrowserState extends State<AlbumShareOutlierBrowser> {
}
Widget _buildFileThumbnail(File file) {
final Widget child;
if (file_util.isAlbumFile(widget.account, file)) {
return SizedBox(
width: 56,
height: 56,
child: Icon(
Icons.photo_album,
size: 32,
color: AppTheme.getUnfocusedIconColor(context),
),
);
child = const Icon(Icons.photo_album, size: 32);
} else {
return CachedNetworkImage(
width: 56,
height: 56,
child = CachedNetworkImage(
cacheManager: ThumbnailCacheManager.inst,
imageUrl: api_util.getFilePreviewUrl(widget.account, file,
width: k.photoThumbSize, height: k.photoThumbSize),
@ -287,13 +268,15 @@ class _AlbumShareOutlierBrowserState extends State<AlbumShareOutlierBrowser> {
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
errorWidget: (context, url, error) => Icon(
Icons.image_not_supported,
size: 32,
color: AppTheme.getUnfocusedIconColor(context),
),
errorWidget: (context, url, error) =>
const Icon(Icons.image_not_supported, size: 32),
);
}
return SizedBox(
width: 56,
height: 56,
child: child,
);
}
String _buildFilename(File file) {
@ -309,34 +292,26 @@ class _AlbumShareOutlierBrowserState extends State<AlbumShareOutlierBrowser> {
}) {
return IconButton(
onPressed: onPressed,
icon: Icon(
Icons.handyman_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
icon: const Icon(Icons.handyman_outlined),
tooltip: L10n.global().fixTooltip,
);
}
Widget _buildProcessingIcon(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(12),
return const Padding(
padding: EdgeInsets.all(12),
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: AppTheme.getUnfocusedIconColor(context),
),
child: CircularProgressIndicator(),
),
);
}
Widget _buildFixedIcon(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(12),
child: Icon(
Icons.check,
color: AppTheme.getUnfocusedIconColor(context),
),
return const Padding(
padding: EdgeInsets.all(12),
child: Icon(Icons.check),
);
}

View file

@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/material3.dart';
/// App bar title with optional subtitle and leading icon
class AppBarTitleContainer extends StatelessWidget {
const AppBarTitleContainer({
super.key,
required this.title,
this.subtitle,
this.icon,
});
@override
Widget build(BuildContext context) {
return Row(
children: [
if (icon != null) ...[
SizedBox(
height: 40,
width: 40,
child: Center(
child: IconTheme(
data: IconThemeData(
size: 24,
color: Theme.of(context).appBarTheme.foregroundColor,
),
child: icon!,
),
),
),
const SizedBox(width: 8),
],
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
DefaultTextStyle(
style: subtitle == null
? Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).appBarTheme.foregroundColor,
)
: Theme.of(context).textTheme.titleMedium!.copyWith(
color: Theme.of(context).appBarTheme.foregroundColor,
),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
child: title,
),
if (subtitle != null)
DefaultTextStyle(
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: M3.of(context).listTile.enabled.supportingText,
),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
child: subtitle!,
),
],
),
),
],
);
}
final Widget title;
final Widget? subtitle;
final Widget? icon;
}

View file

@ -18,7 +18,6 @@ import 'package:nc_photos/language_util.dart' as language_util;
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/inflate_file_descriptor.dart';
import 'package:nc_photos/use_case/update_property.dart';
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
@ -71,15 +70,13 @@ class _ArchiveBrowserState extends State<ArchiveBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ScanAccountDirBloc, ScanAccountDirBlocState>(
return Scaffold(
body: BlocListener<ScanAccountDirBloc, ScanAccountDirBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ScanAccountDirBloc, ScanAccountDirBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ScanAccountDirBloc, ScanAccountDirBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -134,20 +131,13 @@ class _ArchiveBrowserState extends State<ArchiveBrowser>
children: [
buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
),
if (state is ScanAccountDirBlocLoading ||

View file

@ -79,7 +79,7 @@ class AlbumGridItemBuilder {
} catch (_) {
cover = Icon(
Icons.panorama,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
size: 88,
);
}
@ -87,7 +87,7 @@ class AlbumGridItemBuilder {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Container(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
constraints: const BoxConstraints.expand(),
child: cover,
),

View file

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/theme.dart';
class ChangelogArguments {
const ChangelogArguments(this.fromVersion);
@ -30,11 +29,9 @@ class Changelog extends StatelessWidget {
);
@override
build(BuildContext context) => AppTheme(
child: Scaffold(
appBar: _buildAppBar(),
body: Builder(builder: (context) => _buildContent(context)),
),
build(BuildContext context) => Scaffold(
appBar: _buildAppBar(),
body: Builder(builder: (context) => _buildContent(context)),
);
AppBar _buildAppBar() => AppBar(

View file

@ -38,21 +38,20 @@ class CollectionListSmall extends StatelessWidget {
end: Alignment.bottomCenter,
colors: [
Colors.black.withOpacity(0),
Colors.black.withOpacity(.55),
Colors.black.withOpacity(.5),
],
),
),
),
Container(
color: Colors.black.withOpacity(.55),
color: Colors.black.withOpacity(.5),
constraints: const BoxConstraints(minWidth: double.infinity),
padding: const EdgeInsets.fromLTRB(8, 0, 8, 4),
child: Text(
label,
style: TextStyle(
color: AppTheme.primaryTextColorDark,
fontWeight: FontWeight.bold,
),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).onDarkSurface,
),
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
@ -80,7 +79,7 @@ class CollectionListSmall extends StatelessWidget {
);
}
return Container(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
constraints: const BoxConstraints.expand(),
child: content,
);

View file

@ -18,7 +18,6 @@ import 'package:nc_photos/mobile/self_signed_cert_manager.dart';
import 'package:nc_photos/platform/features.dart' as features;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/string_extension.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/url_launcher_util.dart';
import 'package:nc_photos/use_case/ls_single_file.dart';
@ -61,14 +60,11 @@ class _ConnectState extends State<Connect> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body:
BlocListener<AppPasswordExchangeBloc, AppPasswordExchangeBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: Builder(builder: (context) => _buildContent(context)),
),
return Scaffold(
body: BlocListener<AppPasswordExchangeBloc, AppPasswordExchangeBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: Builder(builder: (context) => _buildContent(context)),
),
);
}

View file

@ -12,8 +12,8 @@ import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/material3.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:path/path.dart' as path_lib;
class DirPicker extends StatefulWidget {
@ -106,6 +106,7 @@ class DirPickerState extends State<DirPicker> {
// needed to prevent background color overflowing the parent bound, see:
// https://github.com/flutter/flutter/issues/86584
child: Material(
type: MaterialType.transparency,
child: ListView.separated(
key: Key(_currentPath),
itemBuilder: (context, index) {
@ -142,27 +143,38 @@ class DirPickerState extends State<DirPicker> {
final pickState = _isItemPicked(item);
IconData? iconData;
Color? iconColor;
if (canPick) {
switch (pickState) {
case _PickState.picked:
iconData = widget.isMultipleSelections
? Icons.check_box
: Icons.radio_button_checked;
iconColor = CheckboxTheme.of(context)
.fillColor!
.resolve({MaterialState.selected});
break;
case _PickState.childPicked:
iconData = widget.isMultipleSelections
? Icons.indeterminate_check_box
: Icons.remove_circle_outline;
iconColor = CheckboxTheme.of(context)
.fillColor!
.resolve({MaterialState.selected});
break;
case _PickState.notPicked:
default:
iconData = widget.isMultipleSelections
? Icons.check_box_outline_blank
: Icons.radio_button_unchecked;
iconColor = Theme.of(context).colorScheme.onSurface;
break;
}
} else if (item.isE2ee) {
iconData = Icons.lock_outlined;
iconColor = M3.of(context).checkbox.disabled.container;
}
return ListTile(
@ -177,6 +189,7 @@ class DirPickerState extends State<DirPicker> {
child: Icon(
iconData,
key: ValueKey(pickState),
color: iconColor,
),
),
onPressed: () {
@ -188,15 +201,15 @@ class DirPickerState extends State<DirPicker> {
},
)
: IconButton(
icon: Icon(iconData),
color: AppTheme.getUnfocusedIconColor(context),
icon: Icon(iconData, color: iconColor),
onPressed: null,
),
title: Text(item.file.filename),
trailing: item.children?.isNotEmpty == true
? const Icon(Icons.arrow_forward_ios)
: null,
textColor: item.isE2ee ? AppTheme.getUnfocusedIconColor(context) : null,
textColor:
item.isE2ee ? M3.of(context).checkbox.disabled.container : null,
onTap: item.children?.isNotEmpty == true
? () {
try {

View file

@ -26,7 +26,6 @@ import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/preprocess_album.dart';
import 'package:nc_photos/use_case/remove.dart';
import 'package:nc_photos/use_case/update_album.dart';
@ -106,20 +105,18 @@ class _DynamicAlbumBrowserState extends State<DynamicAlbumBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) {
if (isEditMode) {
return Form(
key: _editFormKey,
child: _buildContent(context),
);
} else {
return _buildContent(context);
}
},
),
return Scaffold(
body: Builder(
builder: (context) {
if (isEditMode) {
return Form(
key: _editFormKey,
child: _buildContent(context),
);
} else {
return _buildContent(context);
}
},
),
);
}
@ -214,26 +211,19 @@ class _DynamicAlbumBrowserState extends State<DynamicAlbumBrowser>
}
return buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
SliverIgnorePointer(
ignoring: isEditMode,
sliver: SliverOpacity(
opacity: isEditMode ? .25 : 1,
sliver: buildItemStreamList(
maxCrossAxisExtent: thumbSize.toDouble(),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
SliverIgnorePointer(
ignoring: isEditMode,
sliver: SliverOpacity(
opacity: isEditMode ? .25 : 1,
sliver: buildItemStreamList(
maxCrossAxisExtent: thumbSize.toDouble(),
),
),
],
),
),
],
),
);
}

View file

@ -19,7 +19,6 @@ import 'package:nc_photos/platform/k.dart' as platform_k;
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/empty_list_indicator.dart';
import 'package:nc_photos/widget/handler/delete_local_selection_handler.dart';
import 'package:nc_photos/widget/local_file_viewer.dart';
@ -81,15 +80,13 @@ class _EnhancedPhotoBrowserState extends State<EnhancedPhotoBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ScanLocalDirBloc, ScanLocalDirBlocState>(
return Scaffold(
body: BlocListener<ScanLocalDirBloc, ScanLocalDirBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ScanLocalDirBloc, ScanLocalDirBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ScanLocalDirBloc, ScanLocalDirBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -159,20 +156,13 @@ class _EnhancedPhotoBrowserState extends State<EnhancedPhotoBrowser>
children: [
buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
),
if (state is ScanLocalDirBlocLoading || _buildItemQueue.isProcessing)

View file

@ -69,35 +69,35 @@ class _HomeState extends State<Home> with TickerProviderStateMixin {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
bottomNavigationBar: _buildBottomNavigationBar(context),
body: Builder(builder: (context) => _buildContent(context)),
extendBody: true,
resizeToAvoidBottomInset: false,
),
return Scaffold(
bottomNavigationBar: _buildBottomNavigationBar(context),
body: Builder(builder: (context) => _buildContent(context)),
extendBody: true,
resizeToAvoidBottomInset: false,
);
}
Widget _buildBottomNavigationBar(BuildContext context) {
return BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
return NavigationBar(
destinations: [
NavigationDestination(
icon: const Icon(Icons.photo_outlined),
selectedIcon: const Icon(Icons.photo),
label: L10n.global().photosTabLabel,
),
BottomNavigationBarItem(
NavigationDestination(
icon: const Icon(Icons.search),
label: L10n.global().searchTooltip,
),
BottomNavigationBarItem(
NavigationDestination(
icon: const Icon(Icons.grid_view_outlined),
selectedIcon: const Icon(Icons.grid_view_sharp),
label: L10n.global().collectionsTooltip,
),
],
currentIndex: _nextPage,
onTap: _onTapNavItem,
backgroundColor: Theme.of(context).bottomAppBarColor.withOpacity(.8),
selectedIndex: _nextPage,
onDestinationSelected: _onTapNavItem,
backgroundColor: Theme.of(context).homeNavigationBarBackgroundColor,
);
}

View file

@ -21,7 +21,6 @@ import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/platform/features.dart' as features;
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/remove_album.dart';
import 'package:nc_photos/use_case/unimport_shared_album.dart';
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
@ -115,35 +114,27 @@ class _HomeAlbumsState extends State<HomeAlbums>
children: [
buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
child: RefreshIndicator(
onRefresh: () async {
_onRefreshPressed();
await _waitRefresh();
},
child: CustomScrollView(
slivers: [
_buildAppBar(context),
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 8),
sliver: buildItemStreamList(
maxCrossAxisExtent: 256,
mainAxisSpacing: 6,
),
),
child: RefreshIndicator(
backgroundColor: Colors.grey[100],
onRefresh: () async {
_onRefreshPressed();
await _waitRefresh();
},
child: CustomScrollView(
slivers: [
_buildAppBar(context),
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 8),
sliver: buildItemStreamList(
maxCrossAxisExtent: 256,
mainAxisSpacing: 6,
),
),
SliverToBoxAdapter(
child: SizedBox(
height: _calcBottomAppBarExtent(context),
),
SliverToBoxAdapter(
child: SizedBox(
height: _calcBottomAppBarExtent(context),
),
),
],
),
),
],
),
),
),
@ -499,7 +490,8 @@ class _HomeAlbumsState extends State<HomeAlbums>
}
}
double _calcBottomAppBarExtent(BuildContext context) => kToolbarHeight;
double _calcBottomAppBarExtent(BuildContext context) =>
NavigationBarTheme.of(context).height!;
late final _bloc = ListAlbumBloc.of(widget.account);
late final _accountPrefUpdatedEventListener =
@ -556,7 +548,7 @@ class _ButtonListItem extends _ListItem {
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).colorScheme.outline,
width: 1,
),
borderRadius: BorderRadius.circular(8),
@ -564,19 +556,18 @@ class _ButtonListItem extends _ListItem {
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
child: Row(
children: [
Icon(
icon,
color: AppTheme.getPrimaryTextColor(context),
size: 24,
),
Icon(icon),
const SizedBox(width: 8),
Expanded(
child: Text(label),
child: Text(
label,
style: Theme.of(context).textTheme.labelLarge,
),
),
if (isShowIndicator)
const Icon(
Icon(
Icons.circle,
color: Colors.red,
color: Theme.of(context).colorScheme.tertiary,
size: 8,
),
],

View file

@ -9,6 +9,7 @@ import 'package:nc_photos/pref.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/url_launcher_util.dart';
import 'package:nc_photos/widget/account_picker_dialog.dart';
import 'package:nc_photos/widget/app_bar_title_container.dart';
import 'package:nc_photos/widget/settings.dart';
/// AppBar for home screens
@ -34,46 +35,18 @@ class HomeSliverAppBar extends StatelessWidget {
),
);
},
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: [
Stack(
children: [
if (account.scheme == "http")
const Icon(
Icons.no_encryption_outlined,
color: Colors.orange,
)
else
Icon(
Icons.https,
color: Theme.of(context).colorScheme.primary,
),
],
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
accountLabel ?? account.address,
style: const TextStyle(fontSize: 16),
),
if (accountLabel == null)
Text(
account.username2,
style: TextStyle(
fontSize: 14,
color: AppTheme.getSecondaryTextColor(context),
),
),
],
child: AppBarTitleContainer(
title: Text(accountLabel ?? account.address),
subtitle: accountLabel == null ? Text(account.username2) : null,
icon: account.scheme == "http"
? Icon(
Icons.no_encryption_outlined,
color: Theme.of(context).colorScheme.error,
)
: Icon(
Icons.https,
color: Theme.of(context).colorScheme.primary,
),
),
],
),
),
),
floating: true,
@ -81,18 +54,8 @@ class HomeSliverAppBar extends StatelessWidget {
actions: (actions ?? []) +
[
if (!Pref().isFollowSystemThemeOr(false))
Switch(
value: Theme.of(context).brightness == Brightness.dark,
_DarkModeSwitch(
onChanged: _onDarkModeChanged,
activeColor: AppTheme.getAppBarDarkModeSwitchColor(context),
inactiveThumbColor:
AppTheme.getAppBarDarkModeSwitchColor(context),
activeTrackColor:
AppTheme.getAppBarDarkModeSwitchTrackColor(context),
activeThumbImage:
const AssetImage("assets/ic_dark_mode_switch_24dp.png"),
inactiveThumbImage:
const AssetImage("assets/ic_dark_mode_switch_24dp.png"),
),
PopupMenuButton<int>(
tooltip: MaterialLocalizations.of(context).moreButtonTooltip,
@ -144,3 +107,26 @@ class HomeSliverAppBar extends StatelessWidget {
static const _menuValueAbout = -1;
static const _menuValueHelp = -2;
}
class _DarkModeSwitch extends StatelessWidget {
const _DarkModeSwitch({
this.onChanged,
});
@override
Widget build(BuildContext context) {
return Theme(
data: buildDarkModeSwitchTheme(context),
child: Switch(
value: Theme.of(context).brightness == Brightness.dark,
onChanged: onChanged,
activeThumbImage:
const AssetImage("assets/ic_dark_mode_switch_24dp.png"),
inactiveThumbImage:
const AssetImage("assets/ic_dark_mode_switch_24dp.png"),
),
);
}
final ValueChanged<bool>? onChanged;
}

View file

@ -155,56 +155,49 @@ class _HomePhotosState extends State<HomePhotos>
children: [
buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: DraggableScrollbar.semicircle(
controller: _scrollController,
overrideMaxScrollExtent: scrollExtent,
// status bar + app bar
topOffset: _calcAppBarExtent(context),
bottomOffset: _calcBottomAppBarExtent(context),
labelTextBuilder: (_) => _buildScrollLabel(context),
labelPadding: const EdgeInsets.symmetric(horizontal: 40),
enabled: _isScrollbarVisible,
heightScrollThumb: 60,
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context)
.copyWith(scrollbars: false),
child: RefreshIndicator(
backgroundColor: Colors.grey[100],
onRefresh: () async {
_onRefreshSelected();
await _waitRefresh();
},
child: CustomScrollView(
controller: _scrollController,
slivers: [
_buildAppBar(context),
_web?.buildContent(context),
if (AccountPref.of(widget.account)
.isEnableMemoryAlbumOr(true) &&
_smartAlbums.isNotEmpty)
_buildSmartAlbumList(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
onMaxExtentChanged: (value) {
setState(() {
_itemListMaxExtent = value;
});
},
isEnableVisibilityCallback: true,
child: DraggableScrollbar.semicircle(
controller: _scrollController,
overrideMaxScrollExtent: scrollExtent,
// status bar + app bar
topOffset: _calcAppBarExtent(context),
bottomOffset: _calcBottomAppBarExtent(context),
labelTextBuilder: (_) => _buildScrollLabel(context),
labelPadding: const EdgeInsets.symmetric(horizontal: 40),
backgroundColor: Theme.of(context).colorScheme.inverseSurface,
enabled: _isScrollbarVisible,
heightScrollThumb: 60,
child: ScrollConfiguration(
behavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
child: RefreshIndicator(
onRefresh: () async {
_onRefreshSelected();
await _waitRefresh();
},
child: CustomScrollView(
controller: _scrollController,
slivers: [
_buildAppBar(context),
_web?.buildContent(context),
if (AccountPref.of(widget.account)
.isEnableMemoryAlbumOr(true) &&
_smartAlbums.isNotEmpty)
_buildSmartAlbumList(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
onMaxExtentChanged: (value) {
setState(() {
_itemListMaxExtent = value;
});
},
isEnableVisibilityCallback: true,
),
SliverToBoxAdapter(
child: SizedBox(
height: _calcBottomAppBarExtent(context),
),
SliverToBoxAdapter(
child: SizedBox(
height: _calcBottomAppBarExtent(context),
),
),
].whereType<Widget>().toList(),
),
),
].whereType<Widget>().toList(),
),
),
),
@ -368,10 +361,10 @@ class _HomePhotosState extends State<HomePhotos>
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
text,
style: const TextStyle(
color: AppTheme.primaryTextColorLight,
fontSize: 16,
),
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(color: Theme.of(context).colorScheme.onInverseSurface),
),
);
} else {
@ -684,7 +677,8 @@ class _HomePhotosState extends State<HomePhotos>
double _calcAppBarExtent(BuildContext context) =>
MediaQuery.of(context).padding.top + kToolbarHeight;
double _calcBottomAppBarExtent(BuildContext context) => kToolbarHeight;
double _calcBottomAppBarExtent(BuildContext context) =>
NavigationBarTheme.of(context).height!;
Primitive<bool> get _hasFiredMetadataTask {
final name = bloc_util.getInstNameForRootAwareAccount(
@ -1025,7 +1019,9 @@ class _SmartAlbumItem extends StatelessWidget {
padding: const EdgeInsets.all(4),
child: Text(
label,
style: TextStyle(color: AppTheme.primaryTextColorDark),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).onDarkSurface,
),
),
),
),

View file

@ -74,14 +74,7 @@ class _HomeSearchState extends State<HomeSearch>
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<SearchBloc, SearchBlocState>(
bloc: _bloc,
builder: (context, state) => Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
);
}
@ -330,7 +323,7 @@ class _HomeSearchState extends State<HomeSearch>
return Align(
alignment: Alignment.topCenter,
child: ColoredBox(
color: Theme.of(context).scaffoldBackgroundColor,
color: Theme.of(context).colorScheme.background,
child: SingleChildScrollView(
child: HomeSearchSuggestion(
account: widget.account,
@ -559,7 +552,8 @@ class _HomeSearchState extends State<HomeSearch>
}
}
double _calcBottomAppBarExtent(BuildContext context) => kToolbarHeight;
double _calcBottomAppBarExtent(BuildContext context) =>
NavigationBarTheme.of(context).height!;
bool _isShowLanding(SearchBlocState state) => state is SearchBlocInit;
@ -648,21 +642,18 @@ class _FilterBubbleList extends StatelessWidget {
}
Widget _buildBubble(BuildContext context, String label) {
return Container(
height: 28,
decoration: BoxDecoration(
color: AppTheme.getUnfocusedIconColor(context),
borderRadius: const BorderRadius.all(Radius.circular(14)),
),
padding: const EdgeInsets.symmetric(horizontal: 8),
margin: const EdgeInsets.symmetric(horizontal: 4),
alignment: Alignment.center,
child: Text(
label,
style: TextStyle(
fontSize: 12,
color: AppTheme.getPrimaryTextColorInverse(context),
),
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: FilterChip(
elevation: 1,
pressElevation: 1,
showCheckmark: false,
visualDensity: VisualDensity.compact,
selected: true,
selectedColor:
Theme.of(context).elevate(Theme.of(context).colorScheme.surface, 5),
label: Text(label),
onSelected: (_) {},
),
);
}
@ -807,7 +798,7 @@ class _FilterDropdownState<T> extends State<_FilterDropdown<T>> {
child: Text(
widget.label,
style: TextStyle(
color: AppTheme.getSecondaryTextColor(context),
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),

View file

@ -9,8 +9,8 @@ import 'package:nc_photos/entity/person.dart';
import 'package:nc_photos/entity/tag.dart';
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/list_location_group.dart';
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
import 'package:nc_photos/widget/page_visibility_mixin.dart';
@ -58,11 +58,14 @@ class _HomeSearchSuggestionState extends State<HomeSearchSuggestion>
BlocBuilder<HomeSearchSuggestionBloc, HomeSearchSuggestionBlocState>(
bloc: _bloc,
builder: (context, state) => Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
data: Theme.of(context).run((t) {
return t.copyWith(
listTileTheme: ListTileThemeData(
iconColor: t.colorScheme.onBackground,
textColor: t.colorScheme.onBackground,
),
);
}),
child: _buildContent(context, state),
),
),

View file

@ -12,6 +12,7 @@ import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/help_utils.dart' as help_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/material3.dart';
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/pixel_image_provider.dart';
import 'package:nc_photos/theme.dart';
@ -84,7 +85,8 @@ class _ImageEditorState extends State<ImageEditor> {
}
@override
build(BuildContext context) => AppTheme(
build(BuildContext context) => Theme(
data: buildDarkTheme(),
child: Scaffold(
body: Builder(
builder: _buildContent,
@ -184,8 +186,7 @@ class _ImageEditorState extends State<ImageEditor> {
Widget _buildAppBar(BuildContext context) => AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
leading: BackButton(onPressed: () => _onBackButton(context)),
title: Text(L10n.global().imageEditTitle),
actions: [
@ -359,7 +360,9 @@ class _ToolButton extends StatelessWidget {
onTap: onPressed,
child: Container(
decoration: BoxDecoration(
color: isSelected ? Colors.white24 : null,
color: isSelected
? Theme.of(context).colorScheme.secondaryContainer
: null,
// borderRadius: const BorderRadius.all(Radius.circular(24)),
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
@ -370,8 +373,8 @@ class _ToolButton extends StatelessWidget {
Icon(
icon,
color: isSelected
? Colors.white
: AppTheme.unfocusedIconColorDark,
? Theme.of(context).colorScheme.onSecondaryContainer
: M3.of(context).filterChip.disabled.labelText,
size: 18,
),
const SizedBox(width: 4),
@ -379,8 +382,8 @@ class _ToolButton extends StatelessWidget {
label,
style: TextStyle(
color: isSelected
? Colors.white
: AppTheme.unfocusedIconColorDark,
? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.onSurface,
),
),
],

View file

@ -3,7 +3,6 @@ import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/double_extension.dart';
import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/image_editor/toolbar_button.dart';
import 'package:nc_photos/widget/stateful_slider.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
@ -186,41 +185,39 @@ class _ColorToolbarState extends State<ColorToolbar> {
required double initialValue,
ValueChanged<double>? onChangeEnd,
}) {
return AppTheme.dark(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Stack(
children: [
Align(
alignment: AlignmentDirectional.centerStart,
child: Text(min.toStringAsFixedTruncated(1)),
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Stack(
children: [
Align(
alignment: AlignmentDirectional.centerStart,
child: Text(min.toStringAsFixedTruncated(1)),
),
if (min < 0 && max > 0)
const Align(
alignment: AlignmentDirectional.center,
child: Text("0"),
),
if (min < 0 && max > 0)
const Align(
alignment: AlignmentDirectional.center,
child: Text("0"),
),
Align(
alignment: AlignmentDirectional.centerEnd,
child: Text(max.toStringAsFixedTruncated(1)),
),
],
),
Align(
alignment: AlignmentDirectional.centerEnd,
child: Text(max.toStringAsFixedTruncated(1)),
),
],
),
StatefulSlider(
key: key,
initialValue: initialValue.toDouble(),
min: min.toDouble(),
max: max.toDouble(),
onChangeEnd: onChangeEnd,
),
],
),
),
StatefulSlider(
key: key,
initialValue: initialValue.toDouble(),
min: min.toDouble(),
max: max.toDouble(),
onChangeEnd: onChangeEnd,
),
],
),
);
}

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/material3.dart';
/// Button in the image editor toolbar
///
@ -19,9 +19,19 @@ class ToolbarButton extends StatelessWidget {
@override
build(BuildContext context) {
final color = !isSelected && isActivated
? Colors.white12
: AppTheme.primarySwatchDark[500]!.withOpacity(0.7);
final Color backgroundColor, foregroundColor;
if (isSelected) {
backgroundColor = Theme.of(context).colorScheme.secondaryContainer;
foregroundColor = Theme.of(context).colorScheme.onSecondaryContainer;
} else {
if (isActivated) {
backgroundColor = M3.of(context).filterChip.disabled.containerSelected;
foregroundColor = Theme.of(context).colorScheme.onSurface;
} else {
backgroundColor = Theme.of(context).colorScheme.secondaryContainer;
foregroundColor = M3.of(context).filterChip.disabled.labelText;
}
}
return InkWell(
onTap: onPressed,
child: Padding(
@ -41,7 +51,7 @@ class ToolbarButton extends StatelessWidget {
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
color: color,
color: backgroundColor,
),
),
),
@ -49,9 +59,7 @@ class ToolbarButton extends StatelessWidget {
child: Icon(
icon,
size: 32,
color: isSelected
? Colors.white
: AppTheme.unfocusedIconColorDark,
color: foregroundColor,
),
),
if (isActivated && activationOrder! >= 0)
@ -63,9 +71,7 @@ class ToolbarButton extends StatelessWidget {
(activationOrder! + 1).toString(),
style: TextStyle(
fontSize: 12,
color: isSelected
? Colors.white
: AppTheme.unfocusedIconColorDark,
color: foregroundColor,
),
),
),
@ -79,8 +85,9 @@ class ToolbarButton extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color:
isSelected ? Colors.white : AppTheme.unfocusedIconColorDark,
color: isSelected
? Theme.of(context).colorScheme.onSurface
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],

View file

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/image_editor/toolbar_button.dart';
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
@ -263,7 +262,7 @@ class _OrientationButton extends StatelessWidget {
child: Container(
decoration: BoxDecoration(
color: isSelected
? AppTheme.primarySwatchDark[500]!.withOpacity(0.7)
? Theme.of(context).colorScheme.secondaryContainer
: null,
// borderRadius: const BorderRadius.all(Radius.circular(24)),
),
@ -274,8 +273,8 @@ class _OrientationButton extends StatelessWidget {
textAlign: TextAlign.center,
style: TextStyle(
color: isSelected
? Colors.white
: AppTheme.unfocusedIconColorDark,
? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.onSurface,
),
),
),

View file

@ -82,7 +82,8 @@ class _ImageEnhancerState extends State<ImageEnhancer> {
}
@override
build(BuildContext context) => AppTheme.dark(
build(BuildContext context) => Theme(
data: buildDarkTheme(),
child: Scaffold(
body: Builder(
builder: _buildContent,
@ -131,8 +132,7 @@ class _ImageEnhancerState extends State<ImageEnhancer> {
Widget _buildAppBar(BuildContext context) => AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
title: Text(L10n.global().enhanceTooltip),
actions: [
TextButton(
@ -361,47 +361,39 @@ class _ImageEnhancerState extends State<ImageEnhancer> {
var current = .8;
final iteration = await showDialog<int>(
context: context,
builder: (context) => AppTheme(
child: AlertDialog(
title: Text(L10n.global().enhanceLowLightParamBrightnessLabel),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.brightness_low,
color: AppTheme.getSecondaryTextColor(context),
builder: (context) => AlertDialog(
title: Text(L10n.global().enhanceLowLightParamBrightnessLabel),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
const Icon(Icons.brightness_low),
Expanded(
child: StatefulSlider(
initialValue: current,
onChangeEnd: (value) {
current = value;
},
),
Expanded(
child: StatefulSlider(
initialValue: current,
onChangeEnd: (value) {
current = value;
},
),
),
Icon(
Icons.brightness_high,
color: AppTheme.getSecondaryTextColor(context),
),
],
),
],
),
actions: [
TextButton(
onPressed: () {
final iteration = (current * 10).round().clamp(1, 10);
Navigator.of(context).pop(iteration);
},
child: Text(L10n.global().enhanceButtonLabel),
),
const Icon(Icons.brightness_high),
],
),
],
),
actions: [
TextButton(
onPressed: () {
final iteration = (current * 10).round().clamp(1, 10);
Navigator.of(context).pop(iteration);
},
child: Text(L10n.global().enhanceButtonLabel),
),
],
),
);
_log.info("[_getZeroDceArgs] iteration: $iteration");
@ -413,48 +405,39 @@ class _ImageEnhancerState extends State<ImageEnhancer> {
var current = .5;
final radius = await showDialog<int>(
context: context,
builder: (context) => AppTheme(
child: AlertDialog(
title: Text(L10n.global().enhancePortraitBlurParamBlurLabel),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.circle,
size: 20,
color: AppTheme.getSecondaryTextColor(context),
builder: (context) => AlertDialog(
title: Text(L10n.global().enhancePortraitBlurParamBlurLabel),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
const Icon(Icons.circle, size: 20),
Expanded(
child: StatefulSlider(
initialValue: current,
onChangeEnd: (value) {
current = value;
},
),
Expanded(
child: StatefulSlider(
initialValue: current,
onChangeEnd: (value) {
current = value;
},
),
),
Icon(
Icons.blur_on,
color: AppTheme.getSecondaryTextColor(context),
),
],
),
],
),
actions: [
TextButton(
onPressed: () {
final radius = (current * 25).round().clamp(1, 25);
Navigator.of(context).pop(radius);
},
child: Text(L10n.global().enhanceButtonLabel),
),
const Icon(Icons.blur_on),
],
),
],
),
actions: [
TextButton(
onPressed: () {
final radius = (current * 25).round().clamp(1, 25);
Navigator.of(context).pop(radius);
},
child: Text(L10n.global().enhanceButtonLabel),
),
],
),
);
_log.info("[_getDeepLab3PortraitArgs] radius: $radius");
@ -483,47 +466,38 @@ class _ImageEnhancerState extends State<ImageEnhancer> {
var current = 1.0;
final weight = await showDialog<double>(
context: context,
builder: (context) => AppTheme(
child: AlertDialog(
title: Text(L10n.global().enhanceGenericParamWeightLabel),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.water_drop,
size: 20,
color: AppTheme.getSecondaryTextColor(context),
builder: (context) => AlertDialog(
title: Text(L10n.global().enhanceGenericParamWeightLabel),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
const Icon(Icons.water_drop, size: 20),
Expanded(
child: StatefulSlider(
initialValue: current,
onChangeEnd: (value) {
current = value;
},
),
Expanded(
child: StatefulSlider(
initialValue: current,
onChangeEnd: (value) {
current = value;
},
),
),
Icon(
Icons.water_drop_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
],
),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(current);
},
child: Text(L10n.global().enhanceButtonLabel),
),
const Icon(Icons.water_drop_outlined),
],
),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(current);
},
child: Text(L10n.global().enhanceButtonLabel),
),
],
),
);
_log.info("[_getDeepLab3ColorPopArgs] weight: $weight");
@ -635,14 +609,17 @@ class _ListChild extends StatelessWidget {
child: InkWell(
onTap: onTap,
child: Container(
color: isSelected ? Colors.white24 : null,
color: isSelected
? Theme.of(context).colorScheme.secondaryContainer
: null,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
title,
style: TextStyle(
color:
isSelected ? Colors.white : AppTheme.unfocusedIconColorDark,
color: isSelected
? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.onSurface,
),
),
),
@ -889,106 +866,95 @@ class _StylePicker extends StatefulWidget {
class _StylePickerState extends State<_StylePicker> {
@override
build(BuildContext context) {
return AppTheme(
child: AlertDialog(
title: Text(L10n.global().enhanceStyleTransferStyleDialogTitle),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (_selected != null) ...[
Align(
alignment: Alignment.center,
child: SizedBox(
width: 128,
height: 128,
child: Image(
return AlertDialog(
title: Text(L10n.global().enhanceStyleTransferStyleDialogTitle),
contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 0),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (_selected != null) ...[
Align(
alignment: Alignment.center,
child: SizedBox(
width: 128,
height: 128,
child: Image(
image: ResizeImage.resizeIfNeeded(
128, null, ContentUriImage(_getSelectedUri())),
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 16),
],
Wrap(
runSpacing: 8,
spacing: 8,
children: [
..._bundledStyles.mapIndexed((i, e) => _buildItem(
i,
Image(
image: ResizeImage.resizeIfNeeded(
_thumbSize, null, ContentUriImage(e)),
fit: BoxFit.cover,
),
)),
if (_customUri != null)
_buildItem(
_bundledStyles.length,
Image(
image: ResizeImage.resizeIfNeeded(
128, null, ContentUriImage(_getSelectedUri())),
_thumbSize, null, ContentUriImage(_customUri!)),
fit: BoxFit.cover,
),
),
InkWell(
onTap: _onCustomTap,
child: SizedBox(
width: _thumbSize.toDouble(),
height: _thumbSize.toDouble(),
child: const Icon(Icons.file_open_outlined),
),
),
const SizedBox(height: 16),
],
Wrap(
runSpacing: 8,
spacing: 8,
children: [
..._bundledStyles.mapIndexed((i, e) => _buildItem(
i,
Image(
image: ResizeImage.resizeIfNeeded(
_thumbSize, null, ContentUriImage(e)),
fit: BoxFit.cover,
),
)),
if (_customUri != null)
_buildItem(
_bundledStyles.length,
Image(
image: ResizeImage.resizeIfNeeded(
_thumbSize, null, ContentUriImage(_customUri!)),
fit: BoxFit.cover,
),
),
InkWell(
onTap: _onCustomTap,
child: SizedBox(
width: _thumbSize.toDouble(),
height: _thumbSize.toDouble(),
child: const Icon(
Icons.file_open_outlined,
size: 24,
),
),
),
const SizedBox(height: 16),
Row(
mainAxisSize: MainAxisSize.max,
children: [
const Icon(Icons.auto_fix_normal),
Expanded(
child: StatefulSlider(
initialValue: _weight,
min: .01,
onChangeEnd: (value) {
_weight = value;
},
),
],
),
const SizedBox(height: 16),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.auto_fix_normal,
color: AppTheme.getSecondaryTextColor(context),
),
Expanded(
child: StatefulSlider(
initialValue: _weight,
min: .01,
onChangeEnd: (value) {
_weight = value;
},
),
),
Icon(
Icons.auto_fix_high,
color: AppTheme.getSecondaryTextColor(context),
),
],
),
],
),
actions: [
TextButton(
onPressed: () {
if (_selected == null) {
SnackBarManager().showSnackBar(SnackBar(
content: Text(L10n.global()
.enhanceStyleTransferNoStyleSelectedNotification),
duration: k.snackBarDurationNormal,
));
} else {
final result = _StylePickerResult(_getSelectedUri(), _weight);
Navigator.of(context).pop(result);
}
},
child: Text(L10n.global().enhanceButtonLabel),
),
const Icon(Icons.auto_fix_high),
],
),
],
),
actions: [
TextButton(
onPressed: () {
if (_selected == null) {
SnackBarManager().showSnackBar(SnackBar(
content: Text(L10n.global()
.enhanceStyleTransferNoStyleSelectedNotification),
duration: k.snackBarDurationNormal,
));
} else {
final result = _StylePickerResult(_getSelectedUri(), _weight);
Navigator.of(context).pop(result);
}
},
child: Text(L10n.global().enhanceButtonLabel),
),
],
);
}

View file

@ -48,7 +48,8 @@ class LocalFileViewer extends StatefulWidget {
class _LocalFileViewerState extends State<LocalFileViewer> {
@override
build(BuildContext context) {
return AppTheme(
return Theme(
data: buildDarkTheme(),
child: Scaffold(
body: Builder(
builder: _buildContent,
@ -108,8 +109,7 @@ class _LocalFileViewerState extends State<LocalFileViewer> {
),
AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
actions: [
IconButton(
icon: const Icon(Icons.share),

View file

@ -82,8 +82,8 @@ class _MyAppState extends State<MyApp>
}
return MaterialApp(
onGenerateTitle: (context) => AppLocalizations.of(context)!.appTitle,
theme: AppTheme.buildLightThemeData(),
darkTheme: AppTheme.buildDarkThemeData(),
theme: buildLightTheme(),
darkTheme: buildDarkTheme(),
themeMode: themeMode,
initialRoute: Splash.routeName,
onGenerateRoute: _onGenerateRoute,

View file

@ -58,15 +58,13 @@ class _PeopleBrowserState extends State<PeopleBrowser> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListPersonBloc, ListPersonBlocState>(
return Scaffold(
body: BlocListener<ListPersonBloc, ListPersonBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListPersonBloc, ListPersonBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListPersonBloc, ListPersonBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -89,32 +87,25 @@ class _PeopleBrowserState extends State<PeopleBrowser> {
Widget _buildContent(BuildContext context, ListPersonBlocState state) {
return Stack(
children: [
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
CustomScrollView(
slivers: [
_buildAppBar(context),
if (state is ListPersonBlocLoading)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
if (state is ListPersonBlocLoading)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
SliverStaggeredGrid.extentBuilder(
maxCrossAxisExtent: 160,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
itemCount: _items.length,
itemBuilder: _buildItem,
staggeredTileBuilder: (_) => const StaggeredTile.count(1, 1),
),
],
),
SliverStaggeredGrid.extentBuilder(
maxCrossAxisExtent: 160,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
itemCount: _items.length,
itemBuilder: _buildItem,
staggeredTileBuilder: (_) => const StaggeredTile.count(1, 1),
),
],
),
],
);
@ -213,9 +204,9 @@ class _PersonListItem extends _ListItem {
account: account,
label: name,
coverUrl: faceUrl,
fallbackBuilder: (_) => Icon(
fallbackBuilder: (context) => Icon(
Icons.person,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
onTap: onTap,
);

View file

@ -29,6 +29,7 @@ import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/widget/app_bar_title_container.dart';
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
import 'package:nc_photos/widget/handler/archive_selection_handler.dart';
@ -103,15 +104,13 @@ class _PersonBrowserState extends State<PersonBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListFaceFileBloc, ListFaceFileBlocState>(
return Scaffold(
body: BlocListener<ListFaceFileBloc, ListFaceFileBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListFaceFileBloc, ListFaceFileBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListFaceFileBloc, ListFaceFileBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -137,28 +136,20 @@ class _PersonBrowserState extends State<PersonBrowser>
Widget _buildContent(BuildContext context, ListFaceFileBlocState state) {
return buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
child: CustomScrollView(
slivers: [
_buildAppBar(context, state),
if (state is ListFaceFileBlocLoading || _buildItemQueue.isProcessing)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context, state),
if (state is ListFaceFileBlocLoading ||
_buildItemQueue.isProcessing)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
);
}
@ -175,43 +166,12 @@ class _PersonBrowserState extends State<PersonBrowser>
return SliverAppBar(
floating: true,
titleSpacing: 0,
title: Row(
children: [
SizedBox(
height: 40,
width: 40,
child: _buildFaceImage(context),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget.person.name,
style: TextStyle(
color: AppTheme.getPrimaryTextColor(context),
),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
),
if (state is! ListFaceFileBlocLoading &&
!_buildItemQueue.isProcessing)
Text(
L10n.global().personPhotoCountText(_backingFiles.length),
style: TextStyle(
color: AppTheme.getSecondaryTextColor(context),
fontSize: 12,
),
),
],
),
),
],
title: AppBarTitleContainer(
icon: _buildFaceImage(context),
title: Text(widget.person.name),
subtitle:
Text(L10n.global().personPhotoCountText(_backingFiles.length)),
),
// ),
actions: [
ZoomMenuButton(
initialZoom: _thumbZoomLevel,
@ -254,7 +214,7 @@ class _PersonBrowserState extends State<PersonBrowser>
} catch (_) {
cover = Icon(
Icons.person,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
size: 24,
);
}
@ -262,7 +222,7 @@ class _PersonBrowserState extends State<PersonBrowser>
return ClipRRect(
borderRadius: BorderRadius.circular(64),
child: Container(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
constraints: const BoxConstraints.expand(),
child: cover,
),

View file

@ -171,7 +171,7 @@ class PhotoListLocalImageItem extends PhotoListLocalFileItem {
Container(
// arbitrary size here
constraints: BoxConstraints.tight(const Size(128, 128)),
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
child: Image(
image: ResizeImage.resizeIfNeeded(
k.photoThumbSize, null, provider),
@ -182,7 +182,7 @@ class PhotoListLocalImageItem extends PhotoListLocalFileItem {
child: Icon(
Icons.image_not_supported,
size: 64,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
);
},
@ -223,7 +223,7 @@ class PhotoListImage extends StatelessWidget {
child: Icon(
Icons.image_not_supported,
size: 64,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
);
Widget child;
@ -263,7 +263,7 @@ class PhotoListImage extends StatelessWidget {
Container(
// arbitrary size here
constraints: BoxConstraints.tight(const Size(128, 128)),
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
child: child,
),
if (isGif)
@ -325,7 +325,7 @@ class PhotoListVideo extends StatelessWidget {
Container(
// arbitrary size here
constraints: BoxConstraints.tight(const Size(128, 128)),
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
child: CachedNetworkImage(
cacheManager: ThumbnailCacheManager.inst,
imageUrl: previewUrl,
@ -341,7 +341,7 @@ class PhotoListVideo extends StatelessWidget {
child: Icon(
Icons.image_not_supported,
size: 64,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
);
},
@ -458,10 +458,7 @@ class PhotoListDate extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
subtitle,
style: Theme.of(context).textTheme.caption!.copyWith(
color: AppTheme.getPrimaryTextColor(context),
fontWeight: FontWeight.bold,
),
style: Theme.of(context).textTheme.labelMedium,
),
),
);

View file

@ -20,8 +20,8 @@ import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/about_geocoding_dialog.dart';
import 'package:nc_photos/widget/app_bar_title_container.dart';
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
import 'package:nc_photos/widget/handler/archive_selection_handler.dart';
@ -91,15 +91,13 @@ class _PlaceBrowserState extends State<PlaceBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListLocationFileBloc, ListLocationFileBlocState>(
return Scaffold(
body: BlocListener<ListLocationFileBloc, ListLocationFileBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListLocationFileBloc, ListLocationFileBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListLocationFileBloc, ListLocationFileBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -125,28 +123,21 @@ class _PlaceBrowserState extends State<PlaceBrowser>
Widget _buildContent(BuildContext context, ListLocationFileBlocState state) {
return buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
child: CustomScrollView(
slivers: [
_buildAppBar(context, state),
if (state is ListLocationFileBlocLoading ||
_buildItemQueue.isProcessing)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context, state),
if (state is ListLocationFileBlocLoading ||
_buildItemQueue.isProcessing)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
);
}
@ -164,29 +155,14 @@ class _PlaceBrowserState extends State<PlaceBrowser>
return SliverAppBar(
floating: true,
titleSpacing: 0,
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget.place ?? location_util.alpha2CodeToName(widget.countryCode)!,
style: TextStyle(
color: AppTheme.getPrimaryTextColor(context),
),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
),
if (state is! ListLocationFileBlocLoading &&
!_buildItemQueue.isProcessing)
Text(
L10n.global().personPhotoCountText(_backingFiles.length),
style: TextStyle(
color: AppTheme.getSecondaryTextColor(context),
fontSize: 12,
),
),
],
title: AppBarTitleContainer(
title: Text(
widget.place ?? location_util.alpha2CodeToName(widget.countryCode)!,
),
subtitle: (state is! ListLocationFileBlocLoading &&
!_buildItemQueue.isProcessing)
? Text(L10n.global().personPhotoCountText(_backingFiles.length))
: null,
),
actions: [
ZoomMenuButton(

View file

@ -63,15 +63,13 @@ class _PlacesBrowserState extends State<PlacesBrowser> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListLocationBloc, ListLocationBlocState>(
return Scaffold(
body: BlocListener<ListLocationBloc, ListLocationBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListLocationBloc, ListLocationBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListLocationBloc, ListLocationBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -94,49 +92,41 @@ class _PlacesBrowserState extends State<PlacesBrowser> {
Widget _buildContent(BuildContext context, ListLocationBlocState state) {
return Stack(
children: [
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
if (state is ListLocationBlocLoading)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
SliverToBoxAdapter(
child: SizedBox(
height: 48,
child: ListView.separated(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 8),
itemCount: _countryItems.length,
itemBuilder: (context, i) =>
_countryItems[i].buildWidget(context),
separatorBuilder: (_, __) => const SizedBox(width: 8),
),
),
),
CustomScrollView(
slivers: [
_buildAppBar(context),
if (state is ListLocationBlocLoading)
const SliverToBoxAdapter(
child: SizedBox(height: 8),
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
SliverStaggeredGrid.extentBuilder(
maxCrossAxisExtent: 160,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
itemCount: _placeItems.length,
itemBuilder: (context, i) =>
_placeItems[i].buildWidget(context),
staggeredTileBuilder: (_) => const StaggeredTile.count(1, 1),
SliverToBoxAdapter(
child: SizedBox(
height: 48,
child: ListView.separated(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 8),
itemCount: _countryItems.length,
itemBuilder: (context, i) =>
_countryItems[i].buildWidget(context),
separatorBuilder: (_, __) => const SizedBox(width: 8),
),
),
],
),
),
const SliverToBoxAdapter(
child: SizedBox(height: 8),
),
SliverStaggeredGrid.extentBuilder(
maxCrossAxisExtent: 160,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
itemCount: _placeItems.length,
itemBuilder: (context, i) => _placeItems[i].buildWidget(context),
staggeredTileBuilder: (_) => const StaggeredTile.count(1, 1),
),
],
),
],
);
@ -265,9 +255,9 @@ class _PlaceItem {
account: account,
label: place,
coverUrl: thumbUrl,
fallbackBuilder: (_) => Icon(
fallbackBuilder: (context) => Icon(
Icons.location_on,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
onTap: onTap,
);
@ -303,12 +293,9 @@ class _CountryItem {
},
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
errorWidget: (_, __, ___) => Padding(
padding: const EdgeInsetsDirectional.fromSTEB(8, 8, 0, 8),
child: Icon(
Icons.location_on,
color: AppTheme.getUnfocusedIconColor(context),
),
errorWidget: (_, __, ___) => const Padding(
padding: EdgeInsetsDirectional.fromSTEB(8, 8, 0, 8),
child: Icon(Icons.location_on),
),
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
),
@ -321,7 +308,7 @@ class _CountryItem {
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).colorScheme.outline,
width: 1,
),
borderRadius: BorderRadius.circular(16),

View file

@ -56,12 +56,11 @@ class _ResultViewerState extends State<ResultViewer> {
@override
build(BuildContext context) {
if (_file == null) {
return AppTheme(
return Theme(
data: buildDarkTheme(),
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
shadowColor: Colors.black,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
),
body: Container(

View file

@ -10,7 +10,6 @@ import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/ls_single_file.dart';
import 'package:nc_photos/widget/dir_picker.dart';
import 'package:nc_photos/widget/processing_dialog.dart';
@ -75,10 +74,8 @@ class _RootPickerState extends State<RootPicker> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: _buildContent(context),
),
return Scaffold(
body: _buildContent(context),
);
}

View file

@ -57,14 +57,7 @@ class _SearchLandingState extends State<SearchLanding> {
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<SearchLandingBloc, SearchLandingBlocState>(
bloc: _bloc,
builder: (context, state) => Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
);
}
@ -319,7 +312,7 @@ class _LandingPersonItem {
onTap: onTap,
fallbackBuilder: (_) => Icon(
Icons.person,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
);
@ -344,7 +337,7 @@ class _LandingLocationItem {
onTap: onTap,
fallbackBuilder: (_) => Icon(
Icons.location_on,
color: Colors.white.withOpacity(.8),
color: Theme.of(context).listPlaceholderForegroundColor,
),
);
@ -384,9 +377,7 @@ class _LandingItemWidget extends StatelessWidget {
width: 88,
child: Text(
label + "\n",
style: Theme.of(context).textTheme.bodyText1!.copyWith(
color: AppTheme.getPrimaryTextColor(context),
),
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
@ -408,7 +399,7 @@ class _LandingItemWidget extends StatelessWidget {
Widget _buildCoverImage(BuildContext context) {
Widget cover;
Widget buildPlaceholder() => Padding(
padding: const EdgeInsets.all(4),
padding: const EdgeInsets.all(8),
child: fallbackBuilder(context),
);
try {
@ -436,7 +427,7 @@ class _LandingItemWidget extends StatelessWidget {
return ClipRRect(
borderRadius: BorderRadius.circular(128),
child: Container(
color: AppTheme.getListItemBackgroundColor(context),
color: Theme.of(context).listPlaceholderBackgroundColor,
constraints: const BoxConstraints.expand(),
child: cover,
),

View file

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/theme.dart';
// Overlay a check mark if an item is selected
class Selectable extends StatelessWidget {
@ -23,7 +22,7 @@ class Selectable extends StatelessWidget {
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: AppTheme.getSelectionOverlayColor(context),
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: borderRadius,
),
),
@ -44,12 +43,12 @@ class Selectable extends StatelessWidget {
Icon(
Icons.circle,
size: iconSize,
color: Theme.of(context).colorScheme.primary,
color: Theme.of(context).colorScheme.primaryContainer,
),
Icon(
Icons.check_circle_outlined,
size: iconSize,
color: Colors.white,
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
],
),

View file

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/theme.dart';
class SelectionAppBar extends StatelessWidget {
const SelectionAppBar({
@ -12,20 +11,15 @@ class SelectionAppBar extends StatelessWidget {
@override
build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
appBarTheme: AppTheme.getContextualAppBarTheme(context),
),
child: SliverAppBar(
pinned: true,
leading: IconButton(
icon: const Icon(Icons.close),
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
onPressed: onClosePressed,
),
title: Text(L10n.global().selectionAppBarTitle(count)),
actions: actions,
return SliverAppBar(
pinned: true,
leading: IconButton(
icon: const Icon(Icons.close),
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
onPressed: onClosePressed,
),
title: Text(L10n.global().selectionAppBarTitle(count)),
actions: actions,
);
}

View file

@ -22,7 +22,6 @@ import 'package:nc_photos/platform/notification.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/service.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/url_launcher_util.dart';
import 'package:nc_photos/widget/fancy_option_picker.dart';
import 'package:nc_photos/widget/gps_map.dart';
@ -83,11 +82,9 @@ class _SettingsState extends State<Settings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -104,11 +101,8 @@ class _SettingsState extends State<Settings> {
delegate: SliverChildListDelegate(
[
ListTile(
leading: ListTileCenterLeading(
child: Icon(
Icons.translate_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const ListTileCenterLeading(
child: Icon(Icons.translate_outlined),
),
title: Text(L10n.global().settingsLanguageTitle),
subtitle: Text(language_util.getSelectedLanguage().nativeName),
@ -133,39 +127,27 @@ class _SettingsState extends State<Settings> {
),
_buildSubSettings(
context,
leading: Icon(
Icons.manage_accounts_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.manage_accounts_outlined),
label: L10n.global().settingsAccountTitle,
builder: () => AccountSettingsWidget(account: widget.account),
),
_buildSubSettings(
context,
leading: Icon(
Icons.image_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.image_outlined),
label: L10n.global().photosTabLabel,
description: L10n.global().settingsPhotosDescription,
builder: () => _PhotosSettings(account: widget.account),
),
_buildSubSettings(
context,
leading: Icon(
Icons.photo_album_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.photo_album_outlined),
label: L10n.global().settingsAlbumTitle,
description: L10n.global().settingsAlbumDescription,
builder: () => _AlbumSettings(),
),
_buildSubSettings(
context,
leading: Icon(
Icons.view_carousel_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.view_carousel_outlined),
label: L10n.global().settingsViewerTitle,
description: L10n.global().settingsViewerDescription,
builder: () => _ViewerSettings(),
@ -173,40 +155,28 @@ class _SettingsState extends State<Settings> {
if (features.isSupportEnhancement)
_buildSubSettings(
context,
leading: Icon(
Icons.auto_fix_high_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.auto_fix_high_outlined),
label: L10n.global().settingsImageEditTitle,
description: L10n.global().settingsImageEditDescription,
builder: () => const EnhancementSettings(),
),
_buildSubSettings(
context,
leading: Icon(
Icons.palette_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.palette_outlined),
label: L10n.global().settingsThemeTitle,
description: L10n.global().settingsThemeDescription,
builder: () => _ThemeSettings(),
),
_buildSubSettings(
context,
leading: Icon(
Icons.emoji_symbols_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.emoji_symbols_outlined),
label: L10n.global().settingsMiscellaneousTitle,
builder: () => const _MiscSettings(),
),
if (_enabledExperiments.isNotEmpty)
_buildSubSettings(
context,
leading: Icon(
Icons.science_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.science_outlined),
label: L10n.global().settingsExperimentalTitle,
description: L10n.global().settingsExperimentalDescription,
builder: () => _ExperimentalSettings(),
@ -214,10 +184,7 @@ class _SettingsState extends State<Settings> {
if (_isShowDevSettings)
_buildSubSettings(
context,
leading: Icon(
Icons.code_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
leading: const Icon(Icons.code_outlined),
label: "Developer options",
builder: () => _DevSettings(),
),
@ -332,26 +299,23 @@ class _SettingsState extends State<Settings> {
if (value) {
showDialog(
context: context,
builder: (context) => AppTheme(
child: AlertDialog(
title: Text(L10n.global().exifSupportConfirmationDialogTitle),
content: Text(L10n.global().exifSupportDetails),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child:
Text(MaterialLocalizations.of(context).cancelButtonLabel),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().enableButtonLabel),
),
],
),
builder: (context) => AlertDialog(
title: Text(L10n.global().exifSupportConfirmationDialogTitle),
content: Text(L10n.global().exifSupportDetails),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().enableButtonLabel),
),
],
),
).then((value) {
if (value == true) {
@ -389,18 +353,16 @@ class _SettingsState extends State<Settings> {
if (value) {
final result = await showDialog<bool>(
context: context,
builder: (context) => AppTheme(
child: AlertDialog(
content: Text(L10n.global().captureLogDetails),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().enableButtonLabel),
),
],
),
builder: (context) => AlertDialog(
content: Text(L10n.global().captureLogDetails),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().enableButtonLabel),
),
],
),
);
if (result == true) {
@ -514,11 +476,9 @@ class _AccountSettingsState extends State<AccountSettingsWidget> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -823,11 +783,9 @@ class _PhotosSettingsState extends State<_PhotosSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -869,24 +827,22 @@ class _PhotosSettingsState extends State<_PhotosSettings> {
var memoriesRange = _memoriesRange;
final result = await showDialog<bool>(
context: context,
builder: (_) => AppTheme(
child: AlertDialog(
content: _MemoriesRangeSlider(
initialRange: _memoriesRange,
onChanged: (value) {
memoriesRange = value;
},
),
contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().applyButtonLabel),
),
],
builder: (_) => AlertDialog(
content: _MemoriesRangeSlider(
initialRange: _memoriesRange,
onChanged: (value) {
memoriesRange = value;
},
),
contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().applyButtonLabel),
),
],
),
);
if (result != true || memoriesRange == _memoriesRange) {
@ -1004,11 +960,9 @@ class _ViewerSettingsState extends State<_ViewerSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1060,55 +1014,46 @@ class _ViewerSettingsState extends State<_ViewerSettings> {
await ScreenBrightness().setScreenBrightness(brightness);
final value = await showDialog<int>(
context: context,
builder: (_) => AppTheme(
child: AlertDialog(
title: Text(L10n.global().settingsScreenBrightnessTitle),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.global().settingsScreenBrightnessDescription),
const SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.brightness_low,
color: AppTheme.getSecondaryTextColor(context),
builder: (_) => AlertDialog(
title: Text(L10n.global().settingsScreenBrightnessTitle),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.global().settingsScreenBrightnessDescription),
const SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.max,
children: [
const Icon(Icons.brightness_low),
Expanded(
child: StatefulSlider(
initialValue: brightness,
min: 0.01,
onChangeEnd: (value) async {
brightness = value;
try {
await ScreenBrightness().setScreenBrightness(value);
} catch (e, stackTrace) {
_log.severe("Failed while setScreenBrightness", e,
stackTrace);
}
},
),
Expanded(
child: StatefulSlider(
initialValue: brightness,
min: 0.01,
onChangeEnd: (value) async {
brightness = value;
try {
await ScreenBrightness()
.setScreenBrightness(value);
} catch (e, stackTrace) {
_log.severe("Failed while setScreenBrightness", e,
stackTrace);
}
},
),
),
Icon(
Icons.brightness_high,
color: AppTheme.getSecondaryTextColor(context),
),
],
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop((brightness * 100).round());
},
child: Text(MaterialLocalizations.of(context).okButtonLabel),
),
const Icon(Icons.brightness_high),
],
),
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop((brightness * 100).round());
},
child: Text(MaterialLocalizations.of(context).okButtonLabel),
),
],
),
);
@ -1218,11 +1163,9 @@ class _AlbumSettingsState extends State<_AlbumSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1299,11 +1242,9 @@ class _EnhancementSettingsState extends State<EnhancementSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1346,34 +1287,32 @@ class _EnhancementSettingsState extends State<EnhancementSettings> {
var height = _maxHeight;
final result = await showDialog<bool>(
context: context,
builder: (_) => AppTheme(
child: AlertDialog(
title: Text(L10n.global().settingsEnhanceMaxResolutionTitle2),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.global().settingsEnhanceMaxResolutionDescription),
const SizedBox(height: 16),
_EnhanceResolutionSlider(
initialWidth: _maxWidth,
initialHeight: _maxHeight,
onChanged: (value) {
width = value.item1;
height = value.item2;
},
)
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
builder: (_) => AlertDialog(
title: Text(L10n.global().settingsEnhanceMaxResolutionTitle2),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(L10n.global().settingsEnhanceMaxResolutionDescription),
const SizedBox(height: 16),
_EnhanceResolutionSlider(
initialWidth: _maxWidth,
initialHeight: _maxHeight,
onChanged: (value) {
width = value.item1;
height = value.item2;
},
child: Text(MaterialLocalizations.of(context).okButtonLabel),
),
)
],
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(MaterialLocalizations.of(context).okButtonLabel),
),
],
),
);
if (result != true || (width == _maxWidth && height == _maxHeight)) {
@ -1538,11 +1477,9 @@ class _ThemeSettingsState extends State<_ThemeSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1645,11 +1582,9 @@ class _MiscSettingsState extends State<_MiscSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1735,11 +1670,9 @@ class _ExperimentalSettingsState extends State<_ExperimentalSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1799,11 +1732,9 @@ class _DevSettings extends StatefulWidget {
class _DevSettingsState extends State<_DevSettings> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -1883,9 +1814,9 @@ Widget _buildCaption(BuildContext context, String label) {
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
label,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
style: Theme.of(context).textTheme.titleMedium!.copyWith(
color: Theme.of(context).colorScheme.primary,
),
),
);
}

View file

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/home.dart';
import 'package:nc_photos/widget/sign_in.dart';
import 'package:page_view_indicators/circle_page_indicator.dart';
@ -23,11 +22,9 @@ class Setup extends StatefulWidget {
class _SetupState extends State<Setup> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
appBar: _buildAppBar(context),
body: Builder(builder: (context) => _buildContent(context)),
),
return Scaffold(
appBar: _buildAppBar(context),
body: Builder(builder: (context) => _buildContent(context)),
);
}

View file

@ -16,7 +16,6 @@ import 'package:nc_photos/entity/sharee.dart';
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/share_album_with_user.dart';
import 'package:nc_photos/use_case/unshare_album_with_user.dart';
import 'package:nc_photos/widget/album_share_outlier_browser.dart';
@ -62,15 +61,13 @@ class _ShareAlbumDialogState extends State<ShareAlbumDialog> {
@override
build(BuildContext context) {
return AppTheme(
child: DialogScaffold(
canPop: _processingSharee.isEmpty,
body: BlocListener<ListShareeBloc, ListShareeBlocState>(
bloc: _shareeBloc,
listener: _onShareeStateChange,
child: Builder(
builder: _buildContent,
),
return DialogScaffold(
canPop: _processingSharee.isEmpty,
body: BlocListener<ListShareeBloc, ListShareeBlocState>(
bloc: _shareeBloc,
listener: _onShareeStateChange,
child: Builder(
builder: _buildContent,
),
),
);
@ -90,14 +87,12 @@ class _ShareAlbumDialogState extends State<ShareAlbumDialog> {
final isProcessing = _processingSharee.any((s) => s == share.shareWith);
final Widget trailing;
if (isProcessing) {
trailing = Padding(
padding: const EdgeInsetsDirectional.only(end: 12),
trailing = const Padding(
padding: EdgeInsetsDirectional.only(end: 12),
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: AppTheme.getUnfocusedIconColor(context),
),
child: CircularProgressIndicator(),
),
);
} else {
@ -263,7 +258,6 @@ class _ShareAlbumDialogState extends State<ShareAlbumDialog> {
action: hasFailure
? SnackBarAction(
label: L10n.global().fixButtonLabel,
textColor: Theme.of(context).colorScheme.secondaryVariant,
onPressed: _onFixPressed,
)
: null,
@ -303,7 +297,6 @@ class _ShareAlbumDialogState extends State<ShareAlbumDialog> {
action: hasFailure
? SnackBarAction(
label: L10n.global().fixButtonLabel,
textColor: Theme.of(context).colorScheme.secondaryVariant,
onPressed: _onFixPressed,
)
: null,

View file

@ -8,7 +8,6 @@ import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/iterable_extension.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/dir_picker.dart';
class ShareFolderPickerArguments {
@ -49,10 +48,8 @@ class ShareFolderPicker extends StatefulWidget {
class _ShareFolderPickerState extends State<ShareFolderPicker> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: _buildContent(context),
),
return Scaffold(
body: _buildContent(context),
);
}

View file

@ -19,7 +19,6 @@ import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/remove.dart';
import 'package:nc_photos/use_case/remove_share.dart';
import 'package:nc_photos/widget/list_tile_center_leading.dart';
@ -67,10 +66,8 @@ class SharedFileViewer extends StatefulWidget {
class _SharedFileViewerState extends State<SharedFileViewer> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: _buildContent(context),
),
return Scaffold(
body: _buildContent(context),
);
}

View file

@ -24,7 +24,6 @@ import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/or_null.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/import_potential_shared_album.dart';
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
import 'package:nc_photos/widget/empty_list_indicator.dart';
@ -82,15 +81,13 @@ class _SharingBrowserState extends State<SharingBrowser> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListSharingBloc, ListSharingBlocState>(
return Scaffold(
body: BlocListener<ListSharingBloc, ListSharingBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListSharingBloc, ListSharingBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListSharingBloc, ListSharingBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -117,26 +114,19 @@ class _SharingBrowserState extends State<SharingBrowser> {
} else {
return Stack(
children: [
Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
SliverAppBar(
title: Text(L10n.global().collectionSharingLabel),
floating: true,
CustomScrollView(
slivers: [
SliverAppBar(
title: Text(L10n.global().collectionSharingLabel),
floating: true,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => _buildItem(context, _items[index]),
childCount: _items.length,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => _buildItem(context, _items[index]),
childCount: _items.length,
),
),
],
),
),
],
),
if (state is ListSharingBlocLoading)
const Align(
@ -172,14 +162,10 @@ class _SharingBrowserState extends State<SharingBrowser> {
final firstItem = shares.first as ListSharingFile;
return _ListTile(
leading: shares.first.share.itemType == ShareItemType.folder
? SizedBox(
? const SizedBox(
height: _leadingSize,
width: _leadingSize,
child: Icon(
Icons.folder,
size: 32,
color: AppTheme.getUnfocusedIconColor(context),
),
child: Icon(Icons.folder, size: 32),
)
: CachedNetworkImage(
width: _leadingSize,
@ -195,11 +181,8 @@ class _SharingBrowserState extends State<SharingBrowser> {
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
errorWidget: (context, url, error) => Icon(
Icons.folder,
size: 32,
color: AppTheme.getUnfocusedIconColor(context),
),
errorWidget: (context, url, error) =>
const Icon(Icons.folder, size: 32),
),
label: shares.first.share.filename,
description: shares.first.share.uidOwner == widget.account.userId
@ -207,10 +190,7 @@ class _SharingBrowserState extends State<SharingBrowser> {
: L10n.global().fileLastSharedByOthersDescription(
shares.first.share.displaynameOwner, dateStr),
trailing: (shares.any((element) => element.share.url?.isNotEmpty == true))
? Icon(
Icons.link,
color: AppTheme.getUnfocusedIconColor(context),
)
? const Icon(Icons.link)
: null,
onTap: () {
Navigator.of(context).pushNamed(SharedFileViewer.routeName,
@ -231,14 +211,10 @@ class _SharingBrowserState extends State<SharingBrowser> {
final cover = firstItem.album.coverProvider.getCover(firstItem.album);
return _ListTile(
leading: cover == null
? SizedBox(
? const SizedBox(
height: _leadingSize,
width: _leadingSize,
child: Icon(
Icons.photo_album,
size: 32,
color: AppTheme.getUnfocusedIconColor(context),
),
child: Icon(Icons.photo_album, size: 32),
)
: CachedNetworkImage(
width: _leadingSize,
@ -253,21 +229,15 @@ class _SharingBrowserState extends State<SharingBrowser> {
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
errorWidget: (context, url, error) => Icon(
Icons.photo_album,
size: 32,
color: AppTheme.getUnfocusedIconColor(context),
),
errorWidget: (context, url, error) =>
const Icon(Icons.photo_album, size: 32),
),
label: firstItem.album.name,
description: shares.first.share.uidOwner == widget.account.userId
? L10n.global().fileLastSharedDescription(dateStr)
: L10n.global().albumLastSharedByOthersDescription(
shares.first.share.displaynameOwner, dateStr),
trailing: Icon(
Icons.photo_album_outlined,
color: AppTheme.getUnfocusedIconColor(context),
),
trailing: const Icon(Icons.photo_album_outlined),
onTap: () =>
_onAlbumShareItemTap(context, shares.first as ListSharingAlbum),
);

View file

@ -34,10 +34,8 @@ class SignIn extends StatefulWidget {
class _SignInState extends State<SignIn> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(builder: (context) => _buildContent(context)),
),
return Scaffold(
body: Builder(builder: (context) => _buildContent(context)),
);
}
@ -84,16 +82,20 @@ class _SignInState extends State<SignIn> {
Align(
alignment: Alignment.center,
child: Container(
constraints: const BoxConstraints(
maxWidth: AppTheme.widthLimitedContentMaxWidth),
constraints: BoxConstraints(
maxWidth:
Theme.of(context).widthLimitedContentMaxWidth,
),
padding: const EdgeInsets.symmetric(horizontal: 32),
child: _buildForm(context),
),
),
Container(
alignment: AlignmentDirectional.centerStart,
constraints: const BoxConstraints(
maxWidth: AppTheme.widthLimitedContentMaxWidth),
constraints: BoxConstraints(
maxWidth:
Theme.of(context).widthLimitedContentMaxWidth,
),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: InkWell(
onTap: () {
@ -119,8 +121,10 @@ class _SignInState extends State<SignIn> {
),
if (!platform_k.isWeb) Expanded(child: Container()),
Container(
constraints: const BoxConstraints(
maxWidth: AppTheme.widthLimitedContentMaxWidth),
constraints: BoxConstraints(
maxWidth:
Theme.of(context).widthLimitedContentMaxWidth,
),
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,

View file

@ -95,7 +95,8 @@ class _SlideshowViewerState extends State<SlideshowViewer>
@override
build(BuildContext context) {
return AppTheme(
return Theme(
data: buildDarkTheme(),
child: Scaffold(
body: Builder(
builder: _buildContent,
@ -162,8 +163,7 @@ class _SlideshowViewerState extends State<SlideshowViewer>
),
AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.close),
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,

View file

@ -16,7 +16,6 @@ import 'package:nc_photos/flutter_util.dart' as flutter_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/preprocess_album.dart';
import 'package:nc_photos/widget/album_browser_mixin.dart';
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
@ -76,11 +75,9 @@ class _SmartAlbumBrowserState extends State<SmartAlbumBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
return Scaffold(
body: Builder(
builder: (context) => _buildContent(context),
),
);
}
@ -120,20 +117,13 @@ class _SmartAlbumBrowserState extends State<SmartAlbumBrowser>
} else {
return buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: thumbSize.toDouble(),
),
],
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: thumbSize.toDouble(),
),
],
),
);
}

View file

@ -11,7 +11,6 @@ import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/mobile/android/activity.dart';
import 'package:nc_photos/platform/k.dart' as platform_k;
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/compat/v29.dart';
import 'package:nc_photos/use_case/compat/v46.dart';
import 'package:nc_photos/use_case/compat/v55.dart';
@ -58,12 +57,10 @@ class _SplashState extends State<Splash> {
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: WillPopScope(
onWillPop: () => Future.value(false),
child: Builder(builder: (context) => _buildContent(context)),
),
return Scaffold(
body: WillPopScope(
onWillPop: () => Future.value(false),
child: Builder(builder: (context) => _buildContent(context)),
),
);
}

View file

@ -22,8 +22,8 @@ import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/widget/app_bar_title_container.dart';
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
import 'package:nc_photos/widget/handler/archive_selection_handler.dart';
@ -96,15 +96,13 @@ class _TagBrowserState extends State<TagBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<ListTagFileBloc, ListTagFileBlocState>(
return Scaffold(
body: BlocListener<ListTagFileBloc, ListTagFileBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListTagFileBloc, ListTagFileBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<ListTagFileBloc, ListTagFileBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -130,27 +128,20 @@ class _TagBrowserState extends State<TagBrowser>
Widget _buildContent(BuildContext context, ListTagFileBlocState state) {
return buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
child: CustomScrollView(
slivers: [
_buildAppBar(context, state),
if (state is ListTagFileBlocLoading || _buildItemQueue.isProcessing)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context, state),
if (state is ListTagFileBlocLoading || _buildItemQueue.isProcessing)
const SliverToBoxAdapter(
child: Align(
alignment: Alignment.center,
child: LinearProgressIndicator(),
),
),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
);
}
@ -167,45 +158,14 @@ class _TagBrowserState extends State<TagBrowser>
return SliverAppBar(
floating: true,
titleSpacing: 0,
title: Row(
children: [
const SizedBox(
height: 40,
width: 40,
child: Center(
child: Icon(Icons.local_offer_outlined, size: 24),
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget.tag.displayName,
style: TextStyle(
color: AppTheme.getPrimaryTextColor(context),
),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
),
if (state is! ListTagFileBlocLoading &&
!_buildItemQueue.isProcessing)
Text(
L10n.global().personPhotoCountText(_backingFiles.length),
style: TextStyle(
color: AppTheme.getSecondaryTextColor(context),
fontSize: 12,
),
),
],
),
),
],
title: AppBarTitleContainer(
icon: const Icon(Icons.local_offer_outlined),
title: Text(widget.tag.displayName),
subtitle:
(state is! ListTagFileBlocLoading && !_buildItemQueue.isProcessing)
? Text(L10n.global().personPhotoCountText(_backingFiles.length))
: null,
),
// ),
actions: [
ZoomMenuButton(
initialZoom: _thumbZoomLevel,

View file

@ -11,7 +11,6 @@ import 'package:nc_photos/entity/tag.dart';
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/dialog_scaffold.dart';
class TagPickerDialog extends StatefulWidget {
@ -35,13 +34,11 @@ class _TagPickerDialogState extends State<TagPickerDialog> {
@override
build(BuildContext context) {
return AppTheme(
child: DialogScaffold(
body: BlocListener<ListTagBloc, ListTagBlocState>(
bloc: _bloc,
listener: _onStateChange,
child: Builder(builder: _buildContent),
),
return DialogScaffold(
body: BlocListener<ListTagBloc, ListTagBlocState>(
bloc: _bloc,
listener: _onStateChange,
child: Builder(builder: _buildContent),
),
);
}

View file

@ -19,7 +19,6 @@ import 'package:nc_photos/language_util.dart' as language_util;
import 'package:nc_photos/object_extension.dart';
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/use_case/inflate_file_descriptor.dart';
import 'package:nc_photos/use_case/restore_trashbin.dart';
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
@ -73,15 +72,13 @@ class _TrashbinBrowserState extends State<TrashbinBrowser>
@override
build(BuildContext context) {
return AppTheme(
child: Scaffold(
body: BlocListener<LsTrashbinBloc, LsTrashbinBlocState>(
return Scaffold(
body: BlocListener<LsTrashbinBloc, LsTrashbinBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<LsTrashbinBloc, LsTrashbinBlocState>(
bloc: _bloc,
listener: (context, state) => _onStateChange(context, state),
child: BlocBuilder<LsTrashbinBloc, LsTrashbinBlocState>(
bloc: _bloc,
builder: (context, state) => _buildContent(context, state),
),
builder: (context, state) => _buildContent(context, state),
),
),
);
@ -138,20 +135,13 @@ class _TrashbinBrowserState extends State<TrashbinBrowser>
children: [
buildItemStreamListOuter(
context,
child: Theme(
data: Theme.of(context).copyWith(
colorScheme: Theme.of(context).colorScheme.copyWith(
secondary: AppTheme.getOverscrollIndicatorColor(context),
),
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
child: CustomScrollView(
slivers: [
_buildAppBar(context),
buildItemStreamList(
maxCrossAxisExtent: _thumbSize.toDouble(),
),
],
),
),
if (state is LsTrashbinBlocLoading || _buildItemQueue.isProcessing)

View file

@ -60,7 +60,8 @@ class TrashbinViewer extends StatefulWidget {
class _TrashbinViewerState extends State<TrashbinViewer> {
@override
build(BuildContext context) {
return AppTheme(
return Theme(
data: buildDarkTheme(),
child: Scaffold(
body: Builder(
builder: _buildContent,
@ -120,8 +121,7 @@ class _TrashbinViewerState extends State<TrashbinViewer> {
),
AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
actions: [
IconButton(
icon: const Icon(Icons.restore_outlined),

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/material3.dart';
/// A [ListTile]-like widget with unbounded height
class UnboundedListTile extends StatelessWidget {
@ -28,14 +28,16 @@ class UnboundedListTile extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DefaultTextStyle(
style: Theme.of(context).textTheme.subtitle1!,
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
color: M3.of(context).listTile.enabled.headline,
),
child: title,
),
if (subtitle != null)
DefaultTextStyle(
style: TextStyle(
color: AppTheme.getSecondaryTextColor(context),
),
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: M3.of(context).listTile.enabled.supportingText,
),
child: subtitle!,
),
],

View file

@ -180,10 +180,9 @@ class _VideoViewerState extends State<VideoViewer>
valueListenable: _controller,
builder: (context, VideoPlayerValue value, child) => Text(
_durationToString(value.position),
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(.87),
),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.onSurface,
),
),
),
const SizedBox(width: 8),
@ -192,10 +191,12 @@ class _VideoViewerState extends State<VideoViewer>
_controller,
allowScrubbing: true,
padding: const EdgeInsets.symmetric(vertical: 8),
colors: const VideoProgressColors(
backgroundColor: Colors.white24,
bufferedColor: Colors.white38,
playedColor: Colors.white,
colors: VideoProgressColors(
backgroundColor:
Theme.of(context).colorScheme.surface,
bufferedColor:
Theme.of(context).colorScheme.surfaceVariant,
playedColor: Theme.of(context).colorScheme.primary,
),
),
),
@ -203,10 +204,9 @@ class _VideoViewerState extends State<VideoViewer>
if (_controller.value.duration != Duration.zero)
Text(
_durationToString(_controller.value.duration),
style: TextStyle(
fontSize: 14,
color: Colors.white.withOpacity(.87),
),
style: Theme.of(context).textTheme.labelLarge!.copyWith(
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(width: 4),
Tooltip(
@ -222,8 +222,7 @@ class _VideoViewerState extends State<VideoViewer>
child: Icon(
_controller.value.volume == 0
? Icons.volume_mute_outlined
: Icons.volume_up_outlined,
color: Colors.white.withOpacity(.87),
: Icons.volume_up,
),
),
),

View file

@ -104,16 +104,18 @@ class _ViewerState extends State<Viewer>
@override
build(BuildContext context) {
return AppTheme(
final originalBrightness = Theme.of(context).brightness;
return Theme(
data: buildDarkTheme(),
child: Scaffold(
body: Builder(
builder: _buildContent,
builder: (context) => _buildContent(context, originalBrightness),
),
),
);
}
Widget _buildContent(BuildContext context) {
Widget _buildContent(BuildContext context, Brightness originalBrightness) {
return GestureDetector(
onTap: () {
setState(() {
@ -131,7 +133,8 @@ class _ViewerState extends State<Viewer>
),
HorizontalPageViewer(
pageCount: _streamFilesView.length,
pageBuilder: _buildPage,
pageBuilder: (context, i) =>
_buildPage(context, i, originalBrightness),
initialPage: widget.startIndex,
controller: _viewerController,
viewportFraction: _viewportFraction,
@ -174,8 +177,7 @@ class _ViewerState extends State<Viewer>
),
AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
foregroundColor: Colors.white.withOpacity(.87),
elevation: 0,
actions: [
if (!_isDetailPaneActive && _canOpenDetailPane()) ...[
(_pageStates[index]?.favoriteOverride ??
@ -222,45 +224,30 @@ class _ViewerState extends State<Viewer>
child: ViewerBottomAppBar(
children: [
IconButton(
icon: Icon(
Icons.share_outlined,
color: Colors.white.withOpacity(.87),
),
icon: const Icon(Icons.share_outlined),
tooltip: L10n.global().shareTooltip,
onPressed: () => _onSharePressed(context),
),
if (features.isSupportEnhancement &&
ImageEnhancer.isSupportedFormat(file)) ...[
IconButton(
icon: Icon(
Icons.tune_outlined,
color: Colors.white.withOpacity(.87),
),
icon: const Icon(Icons.tune_outlined),
tooltip: L10n.global().editTooltip,
onPressed: () => _onEditPressed(context),
),
IconButton(
icon: Icon(
Icons.auto_fix_high_outlined,
color: Colors.white.withOpacity(.87),
),
icon: const Icon(Icons.auto_fix_high_outlined),
tooltip: L10n.global().enhanceTooltip,
onPressed: () => _onEnhancePressed(context),
),
],
IconButton(
icon: Icon(
Icons.download_outlined,
color: Colors.white.withOpacity(.87),
),
icon: const Icon(Icons.download_outlined),
tooltip: L10n.global().downloadTooltip,
onPressed: _onDownloadPressed,
),
IconButton(
icon: Icon(
Icons.delete_outlined,
color: Colors.white.withOpacity(.87),
),
icon: const Icon(Icons.delete_outlined),
tooltip: L10n.global().deleteTooltip,
onPressed: () => _onDeletePressed(context),
),
@ -271,7 +258,8 @@ class _ViewerState extends State<Viewer>
);
}
Widget _buildPage(BuildContext context, int index) {
Widget _buildPage(
BuildContext context, int index, Brightness originalBrightness) {
if (_pageStates[index] == null) {
_onCreateNewPage(context, index);
} else if (!_pageStates[index]!.scrollController.hasClients) {
@ -310,31 +298,42 @@ class _ViewerState extends State<Viewer>
});
}
},
child: Container(
alignment: Alignment.topLeft,
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height),
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(4)),
),
margin:
EdgeInsets.only(top: _calcDetailPaneOffset(index)),
// this visibility widget avoids loading the detail pane
// until it's actually opened, otherwise swiping between
// photos will slow down severely
child: Visibility(
visible: _isShowDetailPane,
child: ViewerDetailPane(
account: widget.account,
fd: _streamFilesView[index],
album: widget.album,
onRemoveFromAlbumPressed: _onRemoveFromAlbumPressed,
onArchivePressed: _onArchivePressed,
onUnarchivePressed: _onUnarchivePressed,
onSlideshowPressed: _onSlideshowPressed,
),
child: Theme(
data: buildTheme(originalBrightness),
child: Builder(
builder: (context) {
return Container(
alignment: Alignment.topLeft,
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height,
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(4),
),
),
margin: EdgeInsets.only(
top: _calcDetailPaneOffset(index),
),
// this visibility widget avoids loading the detail pane
// until it's actually opened, otherwise swiping between
// photos will slow down severely
child: Visibility(
visible: _isShowDetailPane,
child: ViewerDetailPane(
account: widget.account,
fd: _streamFilesView[index],
album: widget.album,
onRemoveFromAlbumPressed:
_onRemoveFromAlbumPressed,
onArchivePressed: _onArchivePressed,
onUnarchivePressed: _onUnarchivePressed,
onSlideshowPressed: _onSlideshowPressed,
),
),
);
},
),
),
),

View file

@ -185,11 +185,8 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
),
],
ListTile(
leading: ListTileCenterLeading(
child: Icon(
Icons.image_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const ListTileCenterLeading(
child: Icon(Icons.image_outlined),
),
title: Text(path_lib.basenameWithoutExtension(widget.fd.fdPath)),
subtitle: Text(widget.fd.strippedPath),
@ -197,10 +194,9 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
if (_file != null) ...[
if (!_file!.isOwned(widget.account.userId))
ListTile(
leading: ListTileCenterLeading(
leading: const ListTileCenterLeading(
child: Icon(
Icons.share_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
),
title:
@ -209,38 +205,22 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
),
if (_tags.isNotEmpty)
ListTile(
leading: Icon(
Icons.local_offer_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const Icon(Icons.local_offer_outlined),
title: SizedBox(
height: 40,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: _tags.length,
itemBuilder: (context, index) => Center(
child: Wrap(
children: [
Container(
decoration: BoxDecoration(
color: AppTheme.getUnfocusedIconColor(context),
borderRadius:
const BorderRadius.all(Radius.circular(8)),
),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
alignment: Alignment.center,
child: Text(
_tags[index],
style: TextStyle(
fontSize: 12,
color: AppTheme.getPrimaryTextColorInverse(
context),
),
),
),
],
),
itemBuilder: (context, index) => FilterChip(
elevation: 1,
pressElevation: 1,
showCheckmark: false,
visualDensity: VisualDensity.compact,
selected: true,
selectedColor: Theme.of(context)
.elevate(Theme.of(context).colorScheme.surface, 5),
label: Text(_tags[index]),
onSelected: (_) {},
),
separatorBuilder: (context, index) =>
const SizedBox(width: 8),
@ -249,28 +229,17 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
),
],
ListTile(
leading: Icon(
Icons.calendar_today_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const Icon(Icons.calendar_today_outlined),
title: Text("$dateStr $timeStr"),
trailing: _file == null
? null
: Icon(
Icons.edit_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
trailing: _file == null ? null : const Icon(Icons.edit_outlined),
onTap: _file == null ? null : () => _onDateTimeTap(context),
),
if (_file != null) ...[
if (_file!.metadata?.imageWidth != null &&
_file!.metadata?.imageHeight != null)
ListTile(
leading: ListTileCenterLeading(
child: Icon(
Icons.aspect_ratio,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const ListTileCenterLeading(
child: Icon(Icons.aspect_ratio),
),
title: Text(
"${_file!.metadata!.imageWidth} x ${_file!.metadata!.imageHeight}"),
@ -278,19 +247,13 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
)
else
ListTile(
leading: Icon(
Icons.aspect_ratio,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const Icon(Icons.aspect_ratio),
title: Text(_byteSizeToString(_file!.contentLength ?? 0)),
),
if (_model != null)
ListTile(
leading: ListTileCenterLeading(
child: Icon(
Icons.camera_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const ListTileCenterLeading(
child: Icon(Icons.camera_outlined),
),
title: Text(_model!),
subtitle: _buildCameraSubtitle()
@ -298,18 +261,12 @@ class _ViewerDetailPaneState extends State<ViewerDetailPane> {
),
if (_location?.name != null)
ListTile(
leading: ListTileCenterLeading(
child: Icon(
Icons.location_on_outlined,
color: AppTheme.getSecondaryTextColor(context),
),
leading: const ListTileCenterLeading(
child: Icon(Icons.location_on_outlined),
),
title: Text(L10n.global().gpsPlaceText(_location!.name!)),
subtitle: _location!.toSubtitle()?.run((obj) => Text(obj)),
trailing: Icon(
Icons.info_outline,
color: AppTheme.getSecondaryTextColor(context),
),
trailing: const Icon(Icons.info_outline),
onTap: () {
showDialog(
context: context,
@ -556,6 +513,10 @@ class _DetailPaneButton extends StatelessWidget {
build(BuildContext context) {
return TextButton(
onPressed: onPressed,
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all(Theme.of(context).colorScheme.onSurface),
),
child: SizedBox(
width: 96,
height: 96,
@ -563,18 +524,12 @@ class _DetailPaneButton extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(8, 16, 8, 0),
child: Column(
children: [
Icon(
icon,
color: AppTheme.getSecondaryTextColor(context),
),
Icon(icon),
const SizedBox(height: 4),
Text(
label,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color: AppTheme.getSecondaryTextColor(context),
),
style: Theme.of(context).textTheme.labelMedium,
),
],
),

View file

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/theme.dart';
class ZoomMenuButton extends StatelessWidget {
const ZoomMenuButton({
@ -67,19 +66,17 @@ class _PopupMenuZoomState extends State<_PopupMenuZoom> {
@override
build(BuildContext context) {
return AppTheme(
child: Slider(
value: _value.toDouble(),
min: widget.minValue.toDouble(),
max: widget.maxValue.toDouble(),
divisions: (widget.maxValue - widget.minValue).round(),
onChanged: (value) {
setState(() {
_value = value.round();
});
widget.onChanged?.call(_value);
},
),
return Slider(
value: _value.toDouble(),
min: widget.minValue.toDouble(),
max: widget.maxValue.toDouble(),
divisions: (widget.maxValue - widget.minValue).round(),
onChanged: (value) {
setState(() {
_value = value.round();
});
widget.onChanged?.call(_value);
},
);
}