mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-05-12 11:12:19 -04:00
ui cleanup, new themes
This commit is contained in:
parent
94988718e8
commit
44fe198e5d
31 changed files with 1051 additions and 407 deletions
|
@ -1,6 +1,7 @@
|
|||
import 'package:async_tools/async_tools.dart';
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
@ -47,18 +48,22 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
});
|
||||
}
|
||||
|
||||
Widget _wrapInBox({required Widget child, required Color color}) =>
|
||||
Widget _wrapInBox(
|
||||
{required Widget child,
|
||||
required Color color,
|
||||
required double borderRadius}) =>
|
||||
DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
color: color,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16))),
|
||||
borderRadius: BorderRadius.circular(borderRadius))),
|
||||
child: child);
|
||||
|
||||
Widget _makeAccountWidget(
|
||||
{required String name,
|
||||
required bool selected,
|
||||
required ScaleColor scale,
|
||||
required ScaleConfig scaleConfig,
|
||||
required bool loggedIn,
|
||||
required void Function()? callback,
|
||||
required void Function()? footerCallback}) {
|
||||
|
@ -71,13 +76,37 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
shortname = abbrev;
|
||||
}
|
||||
|
||||
late final Color background;
|
||||
late final Color hoverBackground;
|
||||
late final Color activeBackground;
|
||||
late final Color border;
|
||||
late final Color hoverBorder;
|
||||
late final Color activeBorder;
|
||||
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
|
||||
background = loggedIn ? scale.border : scale.subtleBorder;
|
||||
hoverBackground = background;
|
||||
activeBackground = background;
|
||||
border =
|
||||
selected ? scale.activeElementBackground : scale.elementBackground;
|
||||
hoverBorder = border;
|
||||
activeBorder = border;
|
||||
} else {
|
||||
background =
|
||||
selected ? scale.activeElementBackground : scale.elementBackground;
|
||||
hoverBackground = scale.hoverElementBackground;
|
||||
activeBackground = scale.activeElementBackground;
|
||||
border = loggedIn ? scale.border : scale.subtleBorder;
|
||||
hoverBorder = scale.hoverBorder;
|
||||
activeBorder = scale.primary;
|
||||
}
|
||||
|
||||
final avatar = Container(
|
||||
height: 34,
|
||||
width: 34,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: loggedIn ? scale.border : scale.subtleBorder,
|
||||
color: border,
|
||||
width: 2,
|
||||
strokeAlign: BorderSide.strokeAlignOutside),
|
||||
color: Colors.blue,
|
||||
|
@ -89,27 +118,28 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
child: Text(shortname, style: theme.textTheme.titleLarge)));
|
||||
|
||||
return AnimatedPadding(
|
||||
padding: EdgeInsets.fromLTRB(selected ? 0 : 0, 0, selected ? 0 : 8, 0),
|
||||
padding: EdgeInsets.fromLTRB(selected ? 0 : 8, selected ? 0 : 2,
|
||||
selected ? 0 : 8, selected ? 0 : 2),
|
||||
duration: const Duration(milliseconds: 50),
|
||||
child: MenuItemWidget(
|
||||
title: name,
|
||||
headerWidget: avatar,
|
||||
titleStyle: theme.textTheme.titleLarge!,
|
||||
titleStyle: theme.textTheme.titleSmall!
|
||||
.copyWith(color: scaleConfig.useVisualIndicators ? border : null),
|
||||
foregroundColor: scale.primary,
|
||||
backgroundColor: selected
|
||||
? scale.activeElementBackground
|
||||
: scale.elementBackground,
|
||||
backgroundHoverColor: scale.hoverElementBackground,
|
||||
backgroundFocusColor: scale.activeElementBackground,
|
||||
borderColor: scale.border,
|
||||
borderHoverColor: scale.hoverBorder,
|
||||
borderFocusColor: scale.primary,
|
||||
backgroundColor: background,
|
||||
backgroundHoverColor: hoverBackground,
|
||||
backgroundFocusColor: activeBackground,
|
||||
borderColor: border,
|
||||
borderHoverColor: hoverBorder,
|
||||
borderFocusColor: activeBorder,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||
callback: callback,
|
||||
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
||||
footerCallback: footerCallback,
|
||||
footerButtonIconColor: scale.border,
|
||||
footerButtonIconHoverColor: scale.hoverElementBackground,
|
||||
footerButtonIconFocusColor: scale.activeElementBackground,
|
||||
footerButtonIconColor: border,
|
||||
footerButtonIconHoverColor: hoverBackground,
|
||||
footerButtonIconFocusColor: activeBackground,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -120,6 +150,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
perAccountCollectionBlocMapState}) {
|
||||
final theme = Theme.of(context);
|
||||
final scaleScheme = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final loggedInAccounts = <Widget>[];
|
||||
final loggedOutAccounts = <Widget>[];
|
||||
|
@ -133,11 +164,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
final avAccountRecordState = perAccountState?.avAccountRecordState;
|
||||
if (perAccountState != null && avAccountRecordState != null) {
|
||||
// Account is logged in
|
||||
final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
|
||||
final scale = theme.extension<ScaleScheme>()!.primaryScale;
|
||||
final loggedInAccount = avAccountRecordState.when(
|
||||
data: (value) => _makeAccountWidget(
|
||||
name: value.profile.name,
|
||||
scale: scale,
|
||||
scaleConfig: scaleConfig,
|
||||
selected: superIdentityRecordKey == activeLocalAccount,
|
||||
loggedIn: true,
|
||||
callback: () {
|
||||
|
@ -152,10 +184,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
}),
|
||||
loading: () => _wrapInBox(
|
||||
child: buildProgressIndicator(),
|
||||
color: scaleScheme.grayScale.subtleBorder),
|
||||
color: scaleScheme.grayScale.subtleBorder,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale),
|
||||
error: (err, st) => _wrapInBox(
|
||||
child: errorPage(err, st),
|
||||
color: scaleScheme.errorScale.subtleBorder),
|
||||
color: scaleScheme.errorScale.subtleBorder,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale),
|
||||
);
|
||||
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
|
||||
} else {
|
||||
|
@ -164,6 +198,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
final loggedOutAccount = _makeAccountWidget(
|
||||
name: la.name,
|
||||
scale: scale,
|
||||
scaleConfig: scaleConfig,
|
||||
selected: superIdentityRecordKey == activeLocalAccount,
|
||||
loggedIn: false,
|
||||
callback: () => {_doSwitchClick(superIdentityRecordKey)},
|
||||
|
@ -185,49 +220,77 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
}
|
||||
|
||||
Widget _getButton(
|
||||
{required Icon icon,
|
||||
required ScaleColor scale,
|
||||
required String tooltip,
|
||||
required void Function()? onPressed}) =>
|
||||
IconButton(
|
||||
icon: icon,
|
||||
color: scale.hoverBorder,
|
||||
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return scale.hoverElementBackground;
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return scale.activeElementBackground;
|
||||
}
|
||||
return scale.elementBackground;
|
||||
}), shape: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: scale.hoverBorder),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)));
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: scale.primary),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)));
|
||||
}
|
||||
{required Icon icon,
|
||||
required ScaleColor scale,
|
||||
required ScaleConfig scaleConfig,
|
||||
required String tooltip,
|
||||
required void Function()? onPressed}) {
|
||||
late final Color background;
|
||||
late final Color hoverBackground;
|
||||
late final Color activeBackground;
|
||||
late final Color border;
|
||||
late final Color hoverBorder;
|
||||
late final Color activeBorder;
|
||||
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
|
||||
background = scale.border;
|
||||
hoverBackground = scale.hoverBorder;
|
||||
activeBackground = scale.primary;
|
||||
border = scale.elementBackground;
|
||||
hoverBorder = scale.hoverElementBackground;
|
||||
activeBorder = scale.activeElementBackground;
|
||||
} else {
|
||||
background = scale.elementBackground;
|
||||
hoverBackground = scale.hoverElementBackground;
|
||||
activeBackground = scale.activeElementBackground;
|
||||
border = scale.border;
|
||||
hoverBorder = scale.hoverBorder;
|
||||
activeBorder = scale.primary;
|
||||
}
|
||||
return IconButton(
|
||||
icon: icon,
|
||||
color: border,
|
||||
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return hoverBackground;
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return activeBackground;
|
||||
}
|
||||
return background;
|
||||
}), shape: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: scale.border),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)));
|
||||
})),
|
||||
tooltip: tooltip,
|
||||
onPressed: onPressed);
|
||||
side: BorderSide(color: hoverBorder),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: activeBorder),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||
}
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(color: border),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||
})),
|
||||
tooltip: tooltip,
|
||||
onPressed: onPressed);
|
||||
}
|
||||
|
||||
Widget _getBottomButtons() {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final settingsButton = _getButton(
|
||||
icon: const Icon(Icons.settings),
|
||||
tooltip: translate('menu.settings_tooltip'),
|
||||
scale: scale.tertiaryScale,
|
||||
scaleConfig: scaleConfig,
|
||||
onPressed: () async {
|
||||
await GoRouterHelper(context).push('/settings');
|
||||
}).paddingLTRB(0, 0, 16, 0);
|
||||
|
@ -236,6 +299,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
icon: const Icon(Icons.add),
|
||||
tooltip: translate('menu.add_account_tooltip'),
|
||||
scale: scale.tertiaryScale,
|
||||
scaleConfig: scaleConfig,
|
||||
onPressed: () async {
|
||||
await GoRouterHelper(context).push('/new_account');
|
||||
}).paddingLTRB(0, 0, 16, 0);
|
||||
|
@ -259,53 +323,105 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
scale.tertiaryScale.hoverElementBackground,
|
||||
scale.tertiaryScale.subtleBorder,
|
||||
scale.tertiaryScale.subtleBackground,
|
||||
]);
|
||||
|
||||
return DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
shadows: [
|
||||
BoxShadow(
|
||||
color: scale.tertiaryScale.appBackground,
|
||||
blurRadius: 6,
|
||||
offset: const Offset(
|
||||
0,
|
||||
3,
|
||||
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders)
|
||||
BoxShadow(
|
||||
color: scale.tertiaryScale.primary.darken(80),
|
||||
spreadRadius: 2,
|
||||
)
|
||||
else if (scaleConfig.useVisualIndicators &&
|
||||
scaleConfig.preferBorders)
|
||||
BoxShadow(
|
||||
color: scale.tertiaryScale.border,
|
||||
spreadRadius: 2,
|
||||
)
|
||||
else
|
||||
BoxShadow(
|
||||
color: scale.tertiaryScale.primary.darken(40),
|
||||
blurRadius: 6,
|
||||
offset: const Offset(
|
||||
0,
|
||||
4,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
gradient: gradient,
|
||||
shape: const RoundedRectangleBorder(
|
||||
gradient: scaleConfig.useVisualIndicators ? null : gradient,
|
||||
color: scaleConfig.useVisualIndicators
|
||||
? (scaleConfig.preferBorders
|
||||
? scale.tertiaryScale.appBackground
|
||||
: scale.tertiaryScale.subtleBorder)
|
||||
: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
side: scaleConfig.preferBorders
|
||||
? BorderSide(color: scale.tertiaryScale.primary, width: 2)
|
||||
: BorderSide.none,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(16),
|
||||
bottomRight: Radius.circular(16)))),
|
||||
topRight: Radius.circular(16 * scaleConfig.borderRadiusScale),
|
||||
bottomRight:
|
||||
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
|
||||
child: Column(children: [
|
||||
FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Row(children: [
|
||||
SvgPicture.asset(
|
||||
child: ColorFiltered(
|
||||
colorFilter: ColorFilter.mode(
|
||||
theme.brightness == Brightness.light
|
||||
? scale.tertiaryScale.primary
|
||||
: scale.tertiaryScale.border,
|
||||
scaleConfig.preferBorders
|
||||
? BlendMode.modulate
|
||||
: BlendMode.dst),
|
||||
child: Row(children: [
|
||||
SvgPicture.asset(
|
||||
height: 48,
|
||||
'assets/images/icon.svg',
|
||||
colorFilter: scaleConfig.useVisualIndicators
|
||||
? grayColorFilter
|
||||
: null)
|
||||
.paddingLTRB(0, 0, 16, 0),
|
||||
SvgPicture.asset(
|
||||
height: 48,
|
||||
'assets/images/icon.svg',
|
||||
'assets/images/title.svg',
|
||||
colorFilter: scaleConfig.useVisualIndicators
|
||||
? grayColorFilter
|
||||
: null)
|
||||
.paddingLTRB(0, 0, 16, 0),
|
||||
SvgPicture.asset(
|
||||
height: 48,
|
||||
'assets/images/title.svg',
|
||||
colorFilter:
|
||||
scaleConfig.useVisualIndicators ? grayColorFilter : null),
|
||||
])),
|
||||
: null),
|
||||
]))),
|
||||
const Spacer(),
|
||||
_getAccountList(
|
||||
localAccounts: localAccounts,
|
||||
activeLocalAccount: activeLocalAccount,
|
||||
perAccountCollectionBlocMapState: perAccountCollectionBlocMapState),
|
||||
DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: !scaleConfig.useVisualIndicators
|
||||
? BorderSide.none
|
||||
: scaleConfig.preferBorders
|
||||
? BorderSide(color: scale.tertiaryScale.border)
|
||||
: BorderSide(color: scale.tertiaryScale.primary),
|
||||
borderRadius: BorderRadius.circular(
|
||||
16 * scaleConfig.borderRadiusScale)),
|
||||
color: scaleConfig.preferBorders
|
||||
? Colors.transparent
|
||||
: scale.tertiaryScale.border.withAlpha(0x5F)),
|
||||
child: Column(children: [
|
||||
Text(translate('menu.accounts'),
|
||||
style: theme.textTheme.titleMedium!.copyWith(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.tertiaryScale.border
|
||||
: scale.tertiaryScale.primary))
|
||||
.paddingLTRB(0, 0, 0, 16),
|
||||
_getAccountList(
|
||||
localAccounts: localAccounts,
|
||||
activeLocalAccount: activeLocalAccount,
|
||||
perAccountCollectionBlocMapState:
|
||||
perAccountCollectionBlocMapState)
|
||||
]).paddingAll(16)),
|
||||
_getBottomButtons(),
|
||||
const Spacer(),
|
||||
Row(children: [
|
||||
Text('Version $packageInfoVersion',
|
||||
Text('${translate('menu.version')} $packageInfoVersion',
|
||||
style: theme.textTheme.labelMedium!
|
||||
.copyWith(color: scale.tertiaryScale.hoverBorder)),
|
||||
const Spacer(),
|
||||
|
@ -315,6 +431,6 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||
),
|
||||
])
|
||||
]).paddingAll(16),
|
||||
);
|
||||
).paddingLTRB(0, 2, 2, 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class MenuItemWidget extends StatelessWidget {
|
||||
const MenuItemWidget({
|
||||
|
@ -17,6 +16,7 @@ class MenuItemWidget extends StatelessWidget {
|
|||
this.borderColor,
|
||||
this.borderHoverColor,
|
||||
this.borderFocusColor,
|
||||
this.borderRadius,
|
||||
this.footerButtonIcon,
|
||||
this.footerButtonIconColor,
|
||||
this.footerButtonIconHoverColor,
|
||||
|
@ -41,18 +41,20 @@ class MenuItemWidget extends StatelessWidget {
|
|||
side: WidgetStateBorderSide.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return borderColor != null
|
||||
? BorderSide(color: borderHoverColor!)
|
||||
? BorderSide(width: 2, color: borderHoverColor!)
|
||||
: null;
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return borderColor != null
|
||||
? BorderSide(color: borderFocusColor!)
|
||||
? BorderSide(width: 2, color: borderFocusColor!)
|
||||
: null;
|
||||
}
|
||||
return borderColor != null ? BorderSide(color: borderColor!) : null;
|
||||
return borderColor != null
|
||||
? BorderSide(width: 2, color: borderColor!)
|
||||
: null;
|
||||
}),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)))),
|
||||
shape: WidgetStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(borderRadius ?? 0)))),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
|
@ -104,6 +106,7 @@ class MenuItemWidget extends StatelessWidget {
|
|||
..add(ColorProperty('backgroundHoverColor', backgroundHoverColor))
|
||||
..add(ColorProperty('backgroundFocusColor', backgroundFocusColor))
|
||||
..add(ColorProperty('borderColor', borderColor))
|
||||
..add(DoubleProperty('borderRadius', borderRadius))
|
||||
..add(ColorProperty('borderHoverColor', borderHoverColor))
|
||||
..add(ColorProperty('borderFocusColor', borderFocusColor));
|
||||
}
|
||||
|
@ -122,6 +125,7 @@ class MenuItemWidget extends StatelessWidget {
|
|||
final Color? backgroundHoverColor;
|
||||
final Color? backgroundFocusColor;
|
||||
final Color? borderColor;
|
||||
final double? borderRadius;
|
||||
final Color? borderHoverColor;
|
||||
final Color? borderFocusColor;
|
||||
final Color? footerButtonIconColor;
|
||||
|
|
|
@ -30,23 +30,39 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||
(c) => c.state.asData!.value.profile);
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return ColoredBox(
|
||||
color: scale.primaryScale.subtleBorder,
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.subtleBackground
|
||||
: scale.primaryScale.subtleBorder,
|
||||
child: Column(children: <Widget>[
|
||||
Row(children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.menu),
|
||||
color: scale.secondaryScale.borderText,
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText,
|
||||
constraints:
|
||||
const BoxConstraints.expand(height: 64, width: 64),
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.all(
|
||||
scale.primaryScale.hoverBorder),
|
||||
scaleConfig.preferBorders
|
||||
? scale.primaryScale.hoverElementBackground
|
||||
: scale.primaryScale.hoverBorder),
|
||||
shape: WidgetStateProperty.all(
|
||||
const RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(16))))),
|
||||
RoundedRectangleBorder(
|
||||
side: !scaleConfig.useVisualIndicators
|
||||
? BorderSide.none
|
||||
: BorderSide(
|
||||
strokeAlign: BorderSide.strokeAlignCenter,
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText,
|
||||
width: 2),
|
||||
borderRadius: BorderRadius.all(Radius.circular(
|
||||
16 * scaleConfig.borderRadiusScale))),
|
||||
)),
|
||||
tooltip: translate('menu.settings_tooltip'),
|
||||
onPressed: () async {
|
||||
final ctrl = context.read<ZoomDrawerController>();
|
||||
|
@ -82,6 +98,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||
final w = MediaQuery.of(context).size.width;
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final children = [
|
||||
ConstrainedBox(
|
||||
|
@ -92,7 +109,10 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||
SizedBox(
|
||||
width: 2,
|
||||
height: double.infinity,
|
||||
child: ColoredBox(color: scale.primaryScale.hoverBorder)),
|
||||
child: ColoredBox(
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.subtleBorder
|
||||
: scale.primaryScale.subtleBackground)),
|
||||
Expanded(child: buildTabletRightPane(context)),
|
||||
];
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ class AccountPageState extends State<AccountPage> {
|
|||
final theme = Theme.of(context);
|
||||
final textTheme = theme.textTheme;
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final cilState = context.watch<ContactInvitationListCubit>().state;
|
||||
final cilBusy = cilState.busy;
|
||||
|
@ -55,10 +56,12 @@ class AccountPageState extends State<AccountPage> {
|
|||
backgroundColor: scale.primaryScale.border,
|
||||
collapsedBackgroundColor: scale.primaryScale.border,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius:
|
||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||
),
|
||||
collapsedShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius:
|
||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||
),
|
||||
title: Text(
|
||||
translate('account_page.contact_invitations'),
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:animated_bottom_navigation_bar/'
|
||||
'animated_bottom_navigation_bar.dart';
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:preload_page_view/preload_page_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
||||
|
||||
import '../../../../chat/chat.dart';
|
||||
import '../../../../contact_invitation/contact_invitation.dart';
|
||||
|
@ -39,7 +41,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
bool onScrollNotification(ScrollNotification notification) {
|
||||
bool _onScrollNotification(ScrollNotification notification) {
|
||||
if (notification is UserScrollNotification &&
|
||||
notification.metrics.axis == Axis.vertical) {
|
||||
switch (notification.direction) {
|
||||
|
@ -58,30 +60,6 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||
return false;
|
||||
}
|
||||
|
||||
BottomBarItem buildBottomBarItem(int index) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
return BottomBarItem(
|
||||
title: Text(_bottomLabelList[index]),
|
||||
icon:
|
||||
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
|
||||
selectedIcon:
|
||||
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
|
||||
backgroundColor: scale.primaryScale.borderText,
|
||||
//badge: const Text('9+'),
|
||||
//showBadge: true,
|
||||
);
|
||||
}
|
||||
|
||||
List<BottomBarItem> _buildBottomBarItems() {
|
||||
final bottomBarItems = List<BottomBarItem>.empty(growable: true);
|
||||
for (var index = 0; index < _bottomLabelList.length; index++) {
|
||||
final item = buildBottomBarItem(index);
|
||||
bottomBarItems.add(item);
|
||||
}
|
||||
return bottomBarItems;
|
||||
}
|
||||
|
||||
Future<void> scanContactInvitationDialog(BuildContext context) async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
|
@ -104,6 +82,63 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||
});
|
||||
}
|
||||
|
||||
Widget _buildBottomBarItem(int index, bool isActive) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
final color = scaleConfig.useVisualIndicators
|
||||
? (scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText)
|
||||
: (isActive
|
||||
? (scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText)
|
||||
: (scaleConfig.preferBorders
|
||||
? scale.primaryScale.subtleBorder
|
||||
: scale.primaryScale.borderText.withAlpha(0x80)));
|
||||
|
||||
final item = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
_selectedIconList[index],
|
||||
size: 24,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Text(
|
||||
_bottomLabelList[index],
|
||||
style: theme.textTheme.labelLarge!.copyWith(
|
||||
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||
color: color),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
if (scaleConfig.useVisualIndicators && isActive) {
|
||||
return DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
14 * scaleConfig.borderRadiusScale),
|
||||
side: BorderSide(
|
||||
width: 2,
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.primaryScale.border
|
||||
: scale.primaryScale.borderText))),
|
||||
child: item)
|
||||
.paddingLTRB(8, 0, 8, 6);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
Widget _bottomSheetBuilder(BuildContext sheetContext, BuildContext context) {
|
||||
if (currentPage == 0) {
|
||||
// New contact invitation
|
||||
|
@ -122,12 +157,13 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return Scaffold(
|
||||
//extendBody: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: NotificationListener<ScrollNotification>(
|
||||
onNotification: onScrollNotification,
|
||||
onNotification: _onScrollNotification,
|
||||
child: PreloadPageView(
|
||||
key: _pageViewKey,
|
||||
controller: pageController,
|
||||
|
@ -148,31 +184,46 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||
// style: Theme.of(context).textTheme.headlineSmall,
|
||||
// ),
|
||||
// ),
|
||||
bottomNavigationBar: StylishBottomBar(
|
||||
backgroundColor: scale.primaryScale.hoverBorder,
|
||||
option: AnimatedBarOptions(
|
||||
inkEffect: true,
|
||||
inkColor: scale.primaryScale.hoverPrimary,
|
||||
opacity: 0.3,
|
||||
),
|
||||
items: _buildBottomBarItems(),
|
||||
hasNotch: true,
|
||||
fabLocation: StylishBarFabLocation.end,
|
||||
currentIndex: currentPage,
|
||||
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
|
||||
itemCount: 2,
|
||||
height: 64,
|
||||
tabBuilder: _buildBottomBarItem,
|
||||
activeIndex: currentPage,
|
||||
gapLocation: GapLocation.end,
|
||||
gapWidth: 90,
|
||||
notchSmoothness: NotchSmoothness.defaultEdge,
|
||||
notchMargin: 4,
|
||||
backgroundColor: scaleConfig.preferBorders
|
||||
? scale.primaryScale.hoverElementBackground
|
||||
: scale.primaryScale.hoverBorder,
|
||||
elevation: 0,
|
||||
onTap: (index) async {
|
||||
await pageController.animateToPage(index,
|
||||
duration: 250.ms, curve: Curves.easeInOut);
|
||||
},
|
||||
),
|
||||
|
||||
floatingActionButton: BottomSheetActionButton(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14))),
|
||||
foregroundColor: scale.secondaryScale.borderText,
|
||||
backgroundColor: scale.secondaryScale.hoverBorder,
|
||||
shape: CircleBorder(
|
||||
side: !scaleConfig.useVisualIndicators
|
||||
? BorderSide.none
|
||||
: BorderSide(
|
||||
strokeAlign: BorderSide.strokeAlignCenter,
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.secondaryScale.border
|
||||
: scale.secondaryScale.borderText,
|
||||
width: 2),
|
||||
),
|
||||
foregroundColor: scaleConfig.preferBorders
|
||||
? scale.secondaryScale.border
|
||||
: scale.secondaryScale.borderText,
|
||||
backgroundColor: scaleConfig.preferBorders
|
||||
? scale.secondaryScale.hoverElementBackground
|
||||
: scale.secondaryScale.hoverBorder,
|
||||
builder: (context) => Icon(
|
||||
_fabIconList[currentPage],
|
||||
color: scale.secondaryScale.borderText,
|
||||
color: scaleConfig.preferBorders
|
||||
? scale.secondaryScale.border
|
||||
: scale.secondaryScale.borderText,
|
||||
),
|
||||
bottomSheetBuilder: (sheetContext) =>
|
||||
_bottomSheetBuilder(sheetContext, context)),
|
||||
|
|
|
@ -118,6 +118,23 @@ class HomeScreenState extends State<HomeScreen>
|
|||
}
|
||||
}
|
||||
|
||||
Widget _applyPageBorder(Widget child) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _zoomDrawerController.stateNotifier!,
|
||||
child: child,
|
||||
builder: (context, drawerState, staticChild) => clipBorder(
|
||||
clipEnabled: drawerState != DrawerState.closed,
|
||||
borderEnabled:
|
||||
scaleConfig.preferBorders && scaleConfig.useVisualIndicators,
|
||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||
borderColor: scale.primaryScale.border,
|
||||
child: staticChild!));
|
||||
}
|
||||
|
||||
Widget _buildAccountPageView(BuildContext context) {
|
||||
final localAccounts = context.watch<LocalAccountsCubit>().state;
|
||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
||||
|
@ -127,7 +144,7 @@ class HomeScreenState extends State<HomeScreen>
|
|||
final activeIndex = localAccounts
|
||||
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
|
||||
if (activeIndex == -1) {
|
||||
return const HomeNoActive();
|
||||
return _applyPageBorder(const HomeNoActive());
|
||||
}
|
||||
|
||||
final accountPages = <Widget>[];
|
||||
|
@ -141,7 +158,7 @@ class HomeScreenState extends State<HomeScreen>
|
|||
}
|
||||
final accountPage = _buildAccountPage(
|
||||
context, superIdentityRecordKey, perAccountCollectionState);
|
||||
accountPages.add(KeyedSubtree.wrap(accountPage, i));
|
||||
accountPages.add(_applyPageBorder(accountPage));
|
||||
}
|
||||
|
||||
return SlideIndexedStack(
|
||||
|
@ -154,15 +171,6 @@ class HomeScreenState extends State<HomeScreen>
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
final gradient = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
scale.tertiaryScale.subtleBackground,
|
||||
scale.tertiaryScale.appBackground,
|
||||
]);
|
||||
|
||||
final localAccounts = context.watch<LocalAccountsCubit>().state;
|
||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
||||
|
@ -171,8 +179,8 @@ class HomeScreenState extends State<HomeScreen>
|
|||
final canClose = activeIndex != -1;
|
||||
|
||||
return SafeArea(
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(gradient: gradient),
|
||||
child: DefaultTextStyle(
|
||||
style: theme.textTheme.bodySmall!,
|
||||
child: ZoomDrawer(
|
||||
controller: _zoomDrawerController,
|
||||
//menuBackgroundColor: Colors.transparent,
|
||||
|
@ -188,18 +196,16 @@ class HomeScreenState extends State<HomeScreen>
|
|||
mainScreen: Provider<ZoomDrawerController>.value(
|
||||
value: _zoomDrawerController,
|
||||
child: Builder(builder: _buildAccountPageView)),
|
||||
borderRadius: 24,
|
||||
//showShadow: false,
|
||||
borderRadius: 0,
|
||||
angle: 0,
|
||||
drawerShadowsBackgroundColor: theme.shadowColor,
|
||||
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x3F),
|
||||
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x2F),
|
||||
openCurve: Curves.fastEaseInToSlowEaseOut,
|
||||
// duration: const Duration(milliseconds: 250),
|
||||
// reverseDuration: const Duration(milliseconds: 250),
|
||||
menuScreenTapClose: canClose,
|
||||
mainScreenTapClose: canClose,
|
||||
disableDragGesture: !canClose,
|
||||
mainScreenScale: .25,
|
||||
mainScreenScale: .15,
|
||||
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
|
||||
)));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue