mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-27 01:14:43 +01:00
Redesign home app bar
This commit is contained in:
parent
e7dd64125e
commit
a17a0432c4
3 changed files with 193 additions and 127 deletions
|
@ -58,6 +58,32 @@ extension ThemeExtension on ThemeData {
|
|||
}
|
||||
}
|
||||
|
||||
class DarkModeSwitchTheme extends StatelessWidget {
|
||||
const DarkModeSwitchTheme({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Theme(
|
||||
data: theme.copyWith(
|
||||
switchTheme: SwitchThemeData(
|
||||
trackColor: MaterialStateProperty.all(theme.colorScheme.surface),
|
||||
thumbColor: MaterialStateProperty.all(Colors.black87),
|
||||
),
|
||||
colorScheme: theme.colorScheme.copyWith(
|
||||
outline: Colors.transparent,
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
final Widget child;
|
||||
}
|
||||
|
||||
ThemeData buildTheme(Brightness brightness) {
|
||||
return (brightness == Brightness.light)
|
||||
? buildLightTheme()
|
||||
|
@ -91,19 +117,6 @@ ThemeData buildDarkTheme() {
|
|||
}
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
colorScheme: theme.colorScheme.copyWith(
|
||||
outline: Colors.transparent,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color getSeedColor() {
|
||||
return Color(Pref().getSeedColor() ?? 0xFF2196F3).withAlpha(0xFF);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:math';
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:clock/clock.dart';
|
||||
import 'package:copy_with/copy_with.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:kiwi/kiwi.dart';
|
||||
|
@ -17,11 +18,13 @@ import 'package:nc_photos/controller/account_controller.dart';
|
|||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/server_status.dart';
|
||||
import 'package:nc_photos/entity/sqlite/database.dart' as sql;
|
||||
import 'package:nc_photos/event/event.dart';
|
||||
import 'package:nc_photos/exception_event.dart';
|
||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||
import 'package:nc_photos/help_utils.dart' as help_util;
|
||||
import 'package:nc_photos/k.dart' as k;
|
||||
import 'package:nc_photos/pref.dart';
|
||||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/toast.dart';
|
||||
import 'package:nc_photos/url_launcher_util.dart';
|
||||
import 'package:nc_photos/widget/home.dart';
|
||||
|
@ -88,69 +91,123 @@ class _WrappedAccountPickerDialog extends StatelessWidget {
|
|||
child: Dialog(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: _BlocBuilder(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.isOpenDropdown != current.isOpenDropdown ||
|
||||
previous.accounts != current.accounts,
|
||||
builder: (context, state) {
|
||||
final bloc = context.read<_Bloc>();
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const _AccountDropdown(),
|
||||
if (state.isOpenDropdown) ...[
|
||||
...state.accounts
|
||||
.where((a) => a.id != bloc.activeAccount.id)
|
||||
.map((a) => _AccountView(account: a)),
|
||||
const _NewAccountView(),
|
||||
] else
|
||||
const _AccountSettingsView(),
|
||||
],
|
||||
);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Center(
|
||||
child: Text(
|
||||
L10n.global().appTitle,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!Pref().isFollowSystemThemeOr(false))
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: _DarkModeSwitch(
|
||||
onChanged: _onDarkModeChanged,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: _BlocBuilder(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.isOpenDropdown !=
|
||||
current.isOpenDropdown ||
|
||||
previous.accounts != current.accounts,
|
||||
builder: (context, state) {
|
||||
final bloc = context.read<_Bloc>();
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const _AccountDropdown(),
|
||||
if (state.isOpenDropdown) ...[
|
||||
...state.accounts
|
||||
.where(
|
||||
(a) => a.id != bloc.activeAccount.id)
|
||||
.map((a) => _AccountView(account: a)),
|
||||
const _NewAccountView(),
|
||||
] else
|
||||
const _AccountSettingsView(),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
_IconTile(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
title: Text(L10n.global().settingsMenuLabel),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
..pop()
|
||||
..pushNamed(
|
||||
Settings.routeName,
|
||||
arguments: SettingsArguments(
|
||||
context.read<_Bloc>().activeAccount),
|
||||
);
|
||||
},
|
||||
),
|
||||
_IconTile(
|
||||
icon: const Icon(Icons.help_outline),
|
||||
title: Text(L10n.global().helpTooltip),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
launch(help_util.mainUrl);
|
||||
},
|
||||
),
|
||||
const _AboutChin(),
|
||||
],
|
||||
_IconTile(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
title: Text(L10n.global().settingsMenuLabel),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
..pop()
|
||||
..pushNamed(
|
||||
Settings.routeName,
|
||||
arguments: SettingsArguments(
|
||||
context.read<_Bloc>().activeAccount),
|
||||
);
|
||||
},
|
||||
),
|
||||
_IconTile(
|
||||
icon: const Icon(Icons.help_outline),
|
||||
title: Text(L10n.global().helpTooltip),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
launch(help_util.mainUrl);
|
||||
},
|
||||
),
|
||||
const _AboutChin(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onDarkModeChanged(bool value) {
|
||||
Pref().setDarkTheme(value).then((_) {
|
||||
KiwiContainer().resolve<EventBus>().fire(ThemeChangedEvent());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _DarkModeSwitch extends StatelessWidget {
|
||||
const _DarkModeSwitch({
|
||||
this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DarkModeSwitchTheme(
|
||||
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;
|
||||
}
|
||||
|
||||
class _AccountDropdown extends StatelessWidget {
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:kiwi/kiwi.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/api/api_util.dart' as api_util;
|
||||
import 'package:nc_photos/event/event.dart';
|
||||
import 'package:nc_photos/pref.dart';
|
||||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/widget/account_picker_dialog.dart';
|
||||
|
@ -58,41 +55,39 @@ class HomeSliverAppBar extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
subtitle: accountLabel == null ? Text(account.username2) : null,
|
||||
icon: isShowProgressIcon
|
||||
? const AppBarCircularProgressIndicator()
|
||||
: _LeadingView(account: account),
|
||||
),
|
||||
),
|
||||
scrolledUnderBackgroundColor:
|
||||
Theme.of(context).homeNavigationBarBackgroundColor,
|
||||
floating: true,
|
||||
automaticallyImplyLeading: false,
|
||||
actions: (actions ?? []) +
|
||||
[
|
||||
if (!Pref().isFollowSystemThemeOr(false))
|
||||
_DarkModeSwitch(
|
||||
onChanged: _onDarkModeChanged,
|
||||
),
|
||||
if (menuActions?.isNotEmpty == true)
|
||||
PopupMenuButton<int>(
|
||||
tooltip: MaterialLocalizations.of(context).moreButtonTooltip,
|
||||
itemBuilder: (_) => menuActions!,
|
||||
onSelected: (option) {
|
||||
if (option >= 0) {
|
||||
onSelectedMenuActions?.call(option);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
actions: [
|
||||
...actions ?? [],
|
||||
if (menuActions?.isNotEmpty == true)
|
||||
PopupMenuButton<int>(
|
||||
tooltip: MaterialLocalizations.of(context).moreButtonTooltip,
|
||||
itemBuilder: (_) => menuActions!,
|
||||
onSelected: (option) {
|
||||
if (option >= 0) {
|
||||
onSelectedMenuActions?.call(option);
|
||||
}
|
||||
},
|
||||
),
|
||||
_ProfileIconView(
|
||||
account: account,
|
||||
isProcessing: isShowProgressIcon,
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => const AccountPickerDialog(),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onDarkModeChanged(bool value) {
|
||||
Pref().setDarkTheme(value).then((_) {
|
||||
KiwiContainer().resolve<EventBus>().fire(ThemeChangedEvent());
|
||||
});
|
||||
}
|
||||
|
||||
final Account account;
|
||||
|
||||
/// Screen specific action buttons
|
||||
|
@ -105,45 +100,46 @@ class HomeSliverAppBar extends StatelessWidget {
|
|||
final bool isShowProgressIcon;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
class _LeadingView extends StatelessWidget {
|
||||
const _LeadingView({
|
||||
class _ProfileIconView extends StatelessWidget {
|
||||
const _ProfileIconView({
|
||||
required this.account,
|
||||
required this.isProcessing,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: api_util.getAccountAvatarUrl(account, 64),
|
||||
fadeInDuration: const Duration(),
|
||||
filterQuality: FilterQuality.high,
|
||||
return SizedBox.square(
|
||||
dimension: _size,
|
||||
child: Stack(
|
||||
children: [
|
||||
isProcessing
|
||||
? const AppBarCircularProgressIndicator()
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(_size / 2),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: api_util.getAccountAvatarUrl(account, 64),
|
||||
fadeInDuration: const Duration(),
|
||||
filterQuality: FilterQuality.high,
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(_size / 2),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final Account account;
|
||||
final bool isProcessing;
|
||||
final VoidCallback onTap;
|
||||
|
||||
static const _size = 40.0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue