ui cleanup, new themes

This commit is contained in:
Christien Rioux 2024-07-06 20:09:18 -04:00
parent 94988718e8
commit 44fe198e5d
31 changed files with 1051 additions and 407 deletions

View File

@ -4,7 +4,9 @@
}, },
"menu": { "menu": {
"settings_tooltip": "Settings", "settings_tooltip": "Settings",
"add_account_tooltip": "Add Account" "add_account_tooltip": "Add Account",
"accounts": "Accounts",
"version": "Version"
}, },
"pager": { "pager": {
"chats": "Chats", "chats": "Chats",
@ -192,6 +194,7 @@
"eggplant": "Eggplant", "eggplant": "Eggplant",
"lime": "Lime", "lime": "Lime",
"grim": "Grim", "grim": "Grim",
"elite": "31337",
"contrast": "Contrast" "contrast": "Contrast"
}, },
"brightness": { "brightness": {

View File

@ -261,7 +261,7 @@ class _EditAccountPageState extends State<EditAccountPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final displayModalHUD = _isInAsyncCall; final displayModalHUD = _isInAsyncCall;
return Scaffold( return StyledScaffold(
// resizeToAvoidBottomInset: false, // resizeToAvoidBottomInset: false,
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: Text(translate('edit_account_page.titlebar')), title: Text(translate('edit_account_page.titlebar')),

View File

@ -93,7 +93,7 @@ class _NewAccountPageState extends State<NewAccountPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final displayModalHUD = _isInAsyncCall; final displayModalHUD = _isInAsyncCall;
return Scaffold( return StyledScaffold(
// resizeToAvoidBottomInset: false, // resizeToAvoidBottomInset: false,
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: Text(translate('new_account_page.titlebar')), title: Text(translate('new_account_page.titlebar')),

View File

@ -21,24 +21,42 @@ class ProfileWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
return DecoratedBox( return DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: scale.primaryScale.border, color: scaleConfig.preferBorders
shape: ? scale.primaryScale.elementBackground
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))), : scale.primaryScale.border,
shape: 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))),
),
child: Column(children: [ child: Column(children: [
Text( Text(
_profile.name, _profile.name,
style: textTheme.headlineSmall! style: textTheme.headlineSmall!.copyWith(
.copyWith(color: scale.primaryScale.borderText), color: scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText),
textAlign: TextAlign.left, textAlign: TextAlign.left,
).paddingAll(4), ).paddingAll(4),
if (_profile.pronouns.isNotEmpty) if (_profile.pronouns.isNotEmpty)
Text(_profile.pronouns, Text(_profile.pronouns,
style: textTheme.bodyMedium! style: textTheme.bodyMedium!.copyWith(
.copyWith(color: scale.primaryScale.borderText)) color: scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText))
.paddingLTRB(4, 0, 4, 4), .paddingLTRB(4, 0, 4, 4),
]), ]),
); );

View File

@ -11,12 +11,12 @@ import 'package:provider/provider.dart';
import 'package:veilid_support/veilid_support.dart'; import 'package:veilid_support/veilid_support.dart';
import 'account_manager/account_manager.dart'; import 'account_manager/account_manager.dart';
import 'account_manager/cubits/active_local_account_cubit.dart';
import 'init.dart'; import 'init.dart';
import 'layout/splash.dart'; import 'layout/splash.dart';
import 'router/router.dart'; import 'router/router.dart';
import 'settings/settings.dart'; import 'settings/settings.dart';
import 'theme/models/theme_preference.dart'; import 'theme/models/theme_preference.dart';
import 'theme/theme.dart';
import 'tick.dart'; import 'tick.dart';
import 'tools/loggy.dart'; import 'tools/loggy.dart';
import 'veilid_processor/veilid_processor.dart'; import 'veilid_processor/veilid_processor.dart';
@ -69,9 +69,7 @@ class VeilidChatApp extends StatelessWidget {
}); });
} }
Widget _buildShortcuts( Widget _buildShortcuts({required Widget Function(BuildContext) builder}) =>
{required BuildContext context,
required Widget Function(BuildContext) builder}) =>
ThemeSwitcher( ThemeSwitcher(
builder: (context) => Shortcuts( builder: (context) => Shortcuts(
shortcuts: <LogicalKeySet, Intent>{ shortcuts: <LogicalKeySet, Intent>{
@ -136,25 +134,42 @@ class VeilidChatApp extends StatelessWidget {
accountRepository: AccountRepository.instance, accountRepository: AccountRepository.instance,
locator: context.read)), locator: context.read)),
], ],
child: BackgroundTicker( child:
child: _buildShortcuts( BackgroundTicker(child: _buildShortcuts(builder: (context) {
context: context, final scale = theme.extension<ScaleScheme>()!;
builder: (context) => MaterialApp.router( final scaleConfig = theme.extension<ScaleConfig>()!;
debugShowCheckedModeBanner: false,
routerConfig: final gradient = LinearGradient(
context.read<RouterCubit>().router(), begin: Alignment.topLeft,
title: translate('app.title'), end: Alignment.bottomRight,
theme: theme, colors: scaleConfig.preferBorders &&
localizationsDelegates: [ theme.brightness == Brightness.light
GlobalMaterialLocalizations.delegate, ? [
GlobalWidgetsLocalizations.delegate, scale.grayScale.hoverElementBackground,
FormBuilderLocalizations.delegate, scale.grayScale.subtleBackground,
localizationDelegate ]
], : [
supportedLocales: scale.tertiaryScale.hoverElementBackground,
localizationDelegate.supportedLocales, scale.tertiaryScale.subtleBackground,
locale: localizationDelegate.currentLocale, ]);
))),
return DecoratedBox(
decoration: BoxDecoration(gradient: gradient),
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: context.read<RouterCubit>().router(),
title: translate('app.title'),
theme: theme,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
FormBuilderLocalizations.delegate,
localizationDelegate
],
supportedLocales: localizationDelegate.supportedLocales,
locale: localizationDelegate.currentLocale,
));
})),
)), )),
); );
}); });

View File

@ -154,8 +154,9 @@ class ChatComponentWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final textTheme = Theme.of(context).textTheme; final scaleConfig = theme.extension<ScaleConfig>()!;
final chatTheme = makeChatTheme(scale, textTheme); final textTheme = theme.textTheme;
final chatTheme = makeChatTheme(scale, scaleConfig, textTheme);
final errorChatTheme = (ChatThemeEditor(chatTheme) final errorChatTheme = (ChatThemeEditor(chatTheme)
..inputTextColor = scale.errorScale.primary ..inputTextColor = scale.errorScale.primary
..sendButtonIcon = Image.asset( ..sendButtonIcon = Image.asset(
@ -191,104 +192,99 @@ class ChatComponentWidget extends StatelessWidget {
chatComponentCubit.scrollOffset = 0; chatComponentCubit.scrollOffset = 0;
} }
return DefaultTextStyle( return Align(
style: textTheme.bodySmall!, alignment: AlignmentDirectional.centerEnd,
child: Align( child: Stack(
alignment: AlignmentDirectional.centerEnd, children: [
child: Stack( Column(
children: [ children: [
Column( Container(
children: [ height: 48,
Container( decoration: BoxDecoration(
height: 48, color: scale.primaryScale.subtleBorder,
),
child: Row(children: [
Align(
alignment: AlignmentDirectional.centerStart,
child: Padding(
padding:
const EdgeInsetsDirectional.fromSTEB(16, 0, 16, 0),
child: Text(title,
textAlign: TextAlign.start,
style: textTheme.titleMedium!.copyWith(
color: scale.primaryScale.borderText)),
)),
const Spacer(),
IconButton(
icon: Icon(Icons.close,
color: scale.primaryScale.borderText),
onPressed: () async {
context.read<ActiveChatCubit>().setActiveChat(null);
}).paddingLTRB(16, 0, 16, 0)
]),
),
Expanded(
child: DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
color: scale.primaryScale.subtleBorder, color: scale.primaryScale.subtleBackground),
), child: NotificationListener<ScrollNotification>(
child: Row(children: [ onNotification: (notification) {
Align( if (chatComponentCubit.scrollOffset != 0) {
alignment: AlignmentDirectional.centerStart, return false;
child: Padding( }
padding: const EdgeInsetsDirectional.fromSTEB(
16, 0, 16, 0),
child: Text(title,
textAlign: TextAlign.start,
style: textTheme.titleMedium!.copyWith(
color: scale.primaryScale.borderText)),
)),
const Spacer(),
IconButton(
icon: Icon(Icons.close,
color: scale.primaryScale.borderText),
onPressed: () async {
context.read<ActiveChatCubit>().setActiveChat(null);
}).paddingLTRB(16, 0, 16, 0)
]),
),
Expanded(
child: DecoratedBox(
decoration: const BoxDecoration(),
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (chatComponentCubit.scrollOffset != 0) {
return false;
}
if (!isFirstPage && if (!isFirstPage &&
notification.metrics.pixels <= notification.metrics.pixels <=
((notification.metrics.maxScrollExtent - ((notification.metrics.maxScrollExtent -
notification.metrics notification
.minScrollExtent) * .metrics.minScrollExtent) *
(1.0 - onEndReachedThreshold) + (1.0 - onEndReachedThreshold) +
notification notification.metrics.minScrollExtent)) {
.metrics.minScrollExtent)) { //
// final scrollOffset =
final scrollOffset = (notification (notification.metrics.maxScrollExtent -
.metrics.maxScrollExtent -
notification.metrics.minScrollExtent) * notification.metrics.minScrollExtent) *
(1.0 - onEndReachedThreshold); (1.0 - onEndReachedThreshold);
chatComponentCubit.scrollOffset = scrollOffset; chatComponentCubit.scrollOffset = scrollOffset;
// //
singleFuture(chatComponentState.chatKey, singleFuture(chatComponentState.chatKey, () async {
() async { await _handlePageForward(chatComponentCubit,
await _handlePageForward(chatComponentCubit, messageWindow, notification);
messageWindow, notification); });
}); } else if (!isLastPage &&
} else if (!isLastPage && notification.metrics.pixels >=
notification.metrics.pixels >= ((notification.metrics.maxScrollExtent -
((notification.metrics.maxScrollExtent - notification
notification.metrics .metrics.minScrollExtent) *
.minScrollExtent) * onEndReachedThreshold +
onEndReachedThreshold + notification.metrics.minScrollExtent)) {
notification //
.metrics.minScrollExtent)) { final scrollOffset =
// -(notification.metrics.maxScrollExtent -
final scrollOffset = -(notification
.metrics.maxScrollExtent -
notification.metrics.minScrollExtent) * notification.metrics.minScrollExtent) *
(1.0 - onEndReachedThreshold); (1.0 - onEndReachedThreshold);
chatComponentCubit.scrollOffset = scrollOffset; chatComponentCubit.scrollOffset = scrollOffset;
// //
singleFuture(chatComponentState.chatKey, singleFuture(chatComponentState.chatKey, () async {
() async { await _handlePageBackward(chatComponentCubit,
await _handlePageBackward(chatComponentCubit, messageWindow, notification);
messageWindow, notification); });
}); }
} return false;
return false; },
}, child: ValueListenableBuilder(
child: ValueListenableBuilder( valueListenable:
valueListenable: chatComponentState.textEditingController,
chatComponentState.textEditingController, builder: (context, textEditingValue, __) {
builder: (context, textEditingValue, __) { final messageIsValid = utf8
final messageIsValid = utf8 .encode(textEditingValue.text)
.encode(textEditingValue.text) .lengthInBytes <
.lengthInBytes < 2048;
2048;
return Chat( return Chat(
key: chatComponentState.chatKey, key: chatComponentState.chatKey,
theme: messageIsValid theme: messageIsValid
? chatTheme ? chatTheme
@ -343,13 +339,14 @@ class ChatComponentWidget extends StatelessWidget {
//showUserAvatars: false, //showUserAvatars: false,
//showUserNames: true, //showUserNames: true,
user: localUser, user: localUser,
emptyState: const EmptyChatWidget()); emptyState: const EmptyChatWidget())
}))), .paddingLTRB(0, 2, 0, 0);
), }))),
],
), ),
], ],
), ),
)); ],
),
);
} }
} }

View File

@ -47,6 +47,7 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
final scaleConfig = theme.extension<ScaleConfig>()!;
final signedContactInvitationBytesV = final signedContactInvitationBytesV =
context.watch<InvitationGeneratorCubit>().state; context.watch<InvitationGeneratorCubit>().state;
@ -59,7 +60,8 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
child: Dialog( child: Dialog(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: const BorderSide(width: 2), side: const BorderSide(width: 2),
borderRadius: BorderRadius.circular(16)), borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale)),
backgroundColor: Colors.white, backgroundColor: Colors.white,
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(

View File

@ -40,13 +40,14 @@ class ContactInvitationListWidgetState
final theme = Theme.of(context); final theme = Theme.of(context);
//final textTheme = theme.textTheme; //final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return Container( return Container(
width: double.infinity, width: double.infinity,
margin: const EdgeInsets.fromLTRB(4, 0, 4, 4), margin: const EdgeInsets.fromLTRB(4, 0, 4, 4),
decoration: ShapeDecoration( decoration: ShapeDecoration(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
)), )),
constraints: const BoxConstraints(maxHeight: 200), constraints: const BoxConstraints(maxHeight: 200),
child: Container( child: Container(
@ -54,7 +55,8 @@ class ContactInvitationListWidgetState
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: scale.primaryScale.subtleBackground, color: scale.primaryScale.subtleBackground,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
)), )),
child: ListView.builder( child: ListView.builder(
controller: _scrollController, controller: _scrollController,

View File

@ -1,6 +1,7 @@
import 'package:async_tools/async_tools.dart'; import 'package:async_tools/async_tools.dart';
import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.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( DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: color, color: color,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16))), borderRadius: BorderRadius.circular(borderRadius))),
child: child); child: child);
Widget _makeAccountWidget( Widget _makeAccountWidget(
{required String name, {required String name,
required bool selected, required bool selected,
required ScaleColor scale, required ScaleColor scale,
required ScaleConfig scaleConfig,
required bool loggedIn, required bool loggedIn,
required void Function()? callback, required void Function()? callback,
required void Function()? footerCallback}) { required void Function()? footerCallback}) {
@ -71,13 +76,37 @@ class _DrawerMenuState extends State<DrawerMenu> {
shortname = abbrev; 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( final avatar = Container(
height: 34, height: 34,
width: 34, width: 34,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(
color: loggedIn ? scale.border : scale.subtleBorder, color: border,
width: 2, width: 2,
strokeAlign: BorderSide.strokeAlignOutside), strokeAlign: BorderSide.strokeAlignOutside),
color: Colors.blue, color: Colors.blue,
@ -89,27 +118,28 @@ class _DrawerMenuState extends State<DrawerMenu> {
child: Text(shortname, style: theme.textTheme.titleLarge))); child: Text(shortname, style: theme.textTheme.titleLarge)));
return AnimatedPadding( 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), duration: const Duration(milliseconds: 50),
child: MenuItemWidget( child: MenuItemWidget(
title: name, title: name,
headerWidget: avatar, headerWidget: avatar,
titleStyle: theme.textTheme.titleLarge!, titleStyle: theme.textTheme.titleSmall!
.copyWith(color: scaleConfig.useVisualIndicators ? border : null),
foregroundColor: scale.primary, foregroundColor: scale.primary,
backgroundColor: selected backgroundColor: background,
? scale.activeElementBackground backgroundHoverColor: hoverBackground,
: scale.elementBackground, backgroundFocusColor: activeBackground,
backgroundHoverColor: scale.hoverElementBackground, borderColor: border,
backgroundFocusColor: scale.activeElementBackground, borderHoverColor: hoverBorder,
borderColor: scale.border, borderFocusColor: activeBorder,
borderHoverColor: scale.hoverBorder, borderRadius: 16 * scaleConfig.borderRadiusScale,
borderFocusColor: scale.primary,
callback: callback, callback: callback,
footerButtonIcon: loggedIn ? Icons.edit_outlined : null, footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
footerCallback: footerCallback, footerCallback: footerCallback,
footerButtonIconColor: scale.border, footerButtonIconColor: border,
footerButtonIconHoverColor: scale.hoverElementBackground, footerButtonIconHoverColor: hoverBackground,
footerButtonIconFocusColor: scale.activeElementBackground, footerButtonIconFocusColor: activeBackground,
)); ));
} }
@ -120,6 +150,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
perAccountCollectionBlocMapState}) { perAccountCollectionBlocMapState}) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scaleScheme = theme.extension<ScaleScheme>()!; final scaleScheme = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final loggedInAccounts = <Widget>[]; final loggedInAccounts = <Widget>[];
final loggedOutAccounts = <Widget>[]; final loggedOutAccounts = <Widget>[];
@ -133,11 +164,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
final avAccountRecordState = perAccountState?.avAccountRecordState; final avAccountRecordState = perAccountState?.avAccountRecordState;
if (perAccountState != null && avAccountRecordState != null) { if (perAccountState != null && avAccountRecordState != null) {
// Account is logged in // Account is logged in
final scale = theme.extension<ScaleScheme>()!.tertiaryScale; final scale = theme.extension<ScaleScheme>()!.primaryScale;
final loggedInAccount = avAccountRecordState.when( final loggedInAccount = avAccountRecordState.when(
data: (value) => _makeAccountWidget( data: (value) => _makeAccountWidget(
name: value.profile.name, name: value.profile.name,
scale: scale, scale: scale,
scaleConfig: scaleConfig,
selected: superIdentityRecordKey == activeLocalAccount, selected: superIdentityRecordKey == activeLocalAccount,
loggedIn: true, loggedIn: true,
callback: () { callback: () {
@ -152,10 +184,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
}), }),
loading: () => _wrapInBox( loading: () => _wrapInBox(
child: buildProgressIndicator(), child: buildProgressIndicator(),
color: scaleScheme.grayScale.subtleBorder), color: scaleScheme.grayScale.subtleBorder,
borderRadius: 16 * scaleConfig.borderRadiusScale),
error: (err, st) => _wrapInBox( error: (err, st) => _wrapInBox(
child: errorPage(err, st), child: errorPage(err, st),
color: scaleScheme.errorScale.subtleBorder), color: scaleScheme.errorScale.subtleBorder,
borderRadius: 16 * scaleConfig.borderRadiusScale),
); );
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8)); loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
} else { } else {
@ -164,6 +198,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
final loggedOutAccount = _makeAccountWidget( final loggedOutAccount = _makeAccountWidget(
name: la.name, name: la.name,
scale: scale, scale: scale,
scaleConfig: scaleConfig,
selected: superIdentityRecordKey == activeLocalAccount, selected: superIdentityRecordKey == activeLocalAccount,
loggedIn: false, loggedIn: false,
callback: () => {_doSwitchClick(superIdentityRecordKey)}, callback: () => {_doSwitchClick(superIdentityRecordKey)},
@ -185,49 +220,77 @@ class _DrawerMenuState extends State<DrawerMenu> {
} }
Widget _getButton( Widget _getButton(
{required Icon icon, {required Icon icon,
required ScaleColor scale, required ScaleColor scale,
required String tooltip, required ScaleConfig scaleConfig,
required void Function()? onPressed}) => required String tooltip,
IconButton( required void Function()? onPressed}) {
icon: icon, late final Color background;
color: scale.hoverBorder, late final Color hoverBackground;
constraints: const BoxConstraints.expand(height: 64, width: 64), late final Color activeBackground;
style: ButtonStyle( late final Color border;
backgroundColor: WidgetStateProperty.resolveWith((states) { late final Color hoverBorder;
if (states.contains(WidgetState.hovered)) { late final Color activeBorder;
return scale.hoverElementBackground; if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
} background = scale.border;
if (states.contains(WidgetState.focused)) { hoverBackground = scale.hoverBorder;
return scale.activeElementBackground; activeBackground = scale.primary;
} border = scale.elementBackground;
return scale.elementBackground; hoverBorder = scale.hoverElementBackground;
}), shape: WidgetStateProperty.resolveWith((states) { activeBorder = scale.activeElementBackground;
if (states.contains(WidgetState.hovered)) { } else {
return RoundedRectangleBorder( background = scale.elementBackground;
side: BorderSide(color: scale.hoverBorder), hoverBackground = scale.hoverElementBackground;
borderRadius: const BorderRadius.all(Radius.circular(16))); activeBackground = scale.activeElementBackground;
} border = scale.border;
if (states.contains(WidgetState.focused)) { hoverBorder = scale.hoverBorder;
return RoundedRectangleBorder( activeBorder = scale.primary;
side: BorderSide(color: scale.primary), }
borderRadius: const BorderRadius.all(Radius.circular(16))); 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( return RoundedRectangleBorder(
side: BorderSide(color: scale.border), side: BorderSide(color: hoverBorder),
borderRadius: const BorderRadius.all(Radius.circular(16))); borderRadius: BorderRadius.all(
})), Radius.circular(16 * scaleConfig.borderRadiusScale)));
tooltip: tooltip, }
onPressed: onPressed); 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() { Widget _getBottomButtons() {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final settingsButton = _getButton( final settingsButton = _getButton(
icon: const Icon(Icons.settings), icon: const Icon(Icons.settings),
tooltip: translate('menu.settings_tooltip'), tooltip: translate('menu.settings_tooltip'),
scale: scale.tertiaryScale, scale: scale.tertiaryScale,
scaleConfig: scaleConfig,
onPressed: () async { onPressed: () async {
await GoRouterHelper(context).push('/settings'); await GoRouterHelper(context).push('/settings');
}).paddingLTRB(0, 0, 16, 0); }).paddingLTRB(0, 0, 16, 0);
@ -236,6 +299,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
tooltip: translate('menu.add_account_tooltip'), tooltip: translate('menu.add_account_tooltip'),
scale: scale.tertiaryScale, scale: scale.tertiaryScale,
scaleConfig: scaleConfig,
onPressed: () async { onPressed: () async {
await GoRouterHelper(context).push('/new_account'); await GoRouterHelper(context).push('/new_account');
}).paddingLTRB(0, 0, 16, 0); }).paddingLTRB(0, 0, 16, 0);
@ -259,53 +323,105 @@ class _DrawerMenuState extends State<DrawerMenu> {
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
colors: [ colors: [
scale.tertiaryScale.hoverElementBackground, scale.tertiaryScale.subtleBorder,
scale.tertiaryScale.subtleBackground, scale.tertiaryScale.subtleBackground,
]); ]);
return DecoratedBox( return DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
shadows: [ shadows: [
BoxShadow( if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders)
color: scale.tertiaryScale.appBackground, BoxShadow(
blurRadius: 6, color: scale.tertiaryScale.primary.darken(80),
offset: const Offset( spreadRadius: 2,
0, )
3, 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, gradient: scaleConfig.useVisualIndicators ? null : gradient,
shape: const RoundedRectangleBorder( 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( borderRadius: BorderRadius.only(
topRight: Radius.circular(16), topRight: Radius.circular(16 * scaleConfig.borderRadiusScale),
bottomRight: Radius.circular(16)))), bottomRight:
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
child: Column(children: [ child: Column(children: [
FittedBox( FittedBox(
fit: BoxFit.scaleDown, fit: BoxFit.scaleDown,
child: Row(children: [ child: ColorFiltered(
SvgPicture.asset( 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, height: 48,
'assets/images/icon.svg', 'assets/images/title.svg',
colorFilter: scaleConfig.useVisualIndicators colorFilter: scaleConfig.useVisualIndicators
? grayColorFilter ? grayColorFilter
: null) : null),
.paddingLTRB(0, 0, 16, 0), ]))),
SvgPicture.asset(
height: 48,
'assets/images/title.svg',
colorFilter:
scaleConfig.useVisualIndicators ? grayColorFilter : null),
])),
const Spacer(), const Spacer(),
_getAccountList( DecoratedBox(
localAccounts: localAccounts, decoration: ShapeDecoration(
activeLocalAccount: activeLocalAccount, shape: RoundedRectangleBorder(
perAccountCollectionBlocMapState: perAccountCollectionBlocMapState), 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(), _getBottomButtons(),
const Spacer(), const Spacer(),
Row(children: [ Row(children: [
Text('Version $packageInfoVersion', Text('${translate('menu.version')} $packageInfoVersion',
style: theme.textTheme.labelMedium! style: theme.textTheme.labelMedium!
.copyWith(color: scale.tertiaryScale.hoverBorder)), .copyWith(color: scale.tertiaryScale.hoverBorder)),
const Spacer(), const Spacer(),
@ -315,6 +431,6 @@ class _DrawerMenuState extends State<DrawerMenu> {
), ),
]) ])
]).paddingAll(16), ]).paddingAll(16),
); ).paddingLTRB(0, 2, 2, 2);
} }
} }

View File

@ -1,7 +1,6 @@
import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class MenuItemWidget extends StatelessWidget { class MenuItemWidget extends StatelessWidget {
const MenuItemWidget({ const MenuItemWidget({
@ -17,6 +16,7 @@ class MenuItemWidget extends StatelessWidget {
this.borderColor, this.borderColor,
this.borderHoverColor, this.borderHoverColor,
this.borderFocusColor, this.borderFocusColor,
this.borderRadius,
this.footerButtonIcon, this.footerButtonIcon,
this.footerButtonIconColor, this.footerButtonIconColor,
this.footerButtonIconHoverColor, this.footerButtonIconHoverColor,
@ -41,18 +41,20 @@ class MenuItemWidget extends StatelessWidget {
side: WidgetStateBorderSide.resolveWith((states) { side: WidgetStateBorderSide.resolveWith((states) {
if (states.contains(WidgetState.hovered)) { if (states.contains(WidgetState.hovered)) {
return borderColor != null return borderColor != null
? BorderSide(color: borderHoverColor!) ? BorderSide(width: 2, color: borderHoverColor!)
: null; : null;
} }
if (states.contains(WidgetState.focused)) { if (states.contains(WidgetState.focused)) {
return borderColor != null return borderColor != null
? BorderSide(color: borderFocusColor!) ? BorderSide(width: 2, color: borderFocusColor!)
: null; : null;
} }
return borderColor != null ? BorderSide(color: borderColor!) : null; return borderColor != null
? BorderSide(width: 2, color: borderColor!)
: null;
}), }),
shape: WidgetStateProperty.all( shape: WidgetStateProperty.all(RoundedRectangleBorder(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)))), borderRadius: BorderRadius.circular(borderRadius ?? 0)))),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: Row( child: Row(
@ -104,6 +106,7 @@ class MenuItemWidget extends StatelessWidget {
..add(ColorProperty('backgroundHoverColor', backgroundHoverColor)) ..add(ColorProperty('backgroundHoverColor', backgroundHoverColor))
..add(ColorProperty('backgroundFocusColor', backgroundFocusColor)) ..add(ColorProperty('backgroundFocusColor', backgroundFocusColor))
..add(ColorProperty('borderColor', borderColor)) ..add(ColorProperty('borderColor', borderColor))
..add(DoubleProperty('borderRadius', borderRadius))
..add(ColorProperty('borderHoverColor', borderHoverColor)) ..add(ColorProperty('borderHoverColor', borderHoverColor))
..add(ColorProperty('borderFocusColor', borderFocusColor)); ..add(ColorProperty('borderFocusColor', borderFocusColor));
} }
@ -122,6 +125,7 @@ class MenuItemWidget extends StatelessWidget {
final Color? backgroundHoverColor; final Color? backgroundHoverColor;
final Color? backgroundFocusColor; final Color? backgroundFocusColor;
final Color? borderColor; final Color? borderColor;
final double? borderRadius;
final Color? borderHoverColor; final Color? borderHoverColor;
final Color? borderFocusColor; final Color? borderFocusColor;
final Color? footerButtonIconColor; final Color? footerButtonIconColor;

View File

@ -30,23 +30,39 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
(c) => c.state.asData!.value.profile); (c) => c.state.asData!.value.profile);
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return ColoredBox( return ColoredBox(
color: scale.primaryScale.subtleBorder, color: scaleConfig.preferBorders
? scale.primaryScale.subtleBackground
: scale.primaryScale.subtleBorder,
child: Column(children: <Widget>[ child: Column(children: <Widget>[
Row(children: [ Row(children: [
IconButton( IconButton(
icon: const Icon(Icons.menu), icon: const Icon(Icons.menu),
color: scale.secondaryScale.borderText, color: scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText,
constraints: constraints:
const BoxConstraints.expand(height: 64, width: 64), const BoxConstraints.expand(height: 64, width: 64),
style: ButtonStyle( style: ButtonStyle(
backgroundColor: WidgetStateProperty.all( backgroundColor: WidgetStateProperty.all(
scale.primaryScale.hoverBorder), scaleConfig.preferBorders
? scale.primaryScale.hoverElementBackground
: scale.primaryScale.hoverBorder),
shape: WidgetStateProperty.all( shape: WidgetStateProperty.all(
const RoundedRectangleBorder( RoundedRectangleBorder(
borderRadius: side: !scaleConfig.useVisualIndicators
BorderRadius.all(Radius.circular(16))))), ? 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'), tooltip: translate('menu.settings_tooltip'),
onPressed: () async { onPressed: () async {
final ctrl = context.read<ZoomDrawerController>(); final ctrl = context.read<ZoomDrawerController>();
@ -82,6 +98,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
final w = MediaQuery.of(context).size.width; final w = MediaQuery.of(context).size.width;
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final children = [ final children = [
ConstrainedBox( ConstrainedBox(
@ -92,7 +109,10 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
SizedBox( SizedBox(
width: 2, width: 2,
height: double.infinity, height: double.infinity,
child: ColoredBox(color: scale.primaryScale.hoverBorder)), child: ColoredBox(
color: scaleConfig.preferBorders
? scale.primaryScale.subtleBorder
: scale.primaryScale.subtleBackground)),
Expanded(child: buildTabletRightPane(context)), Expanded(child: buildTabletRightPane(context)),
]; ];

View File

@ -34,6 +34,7 @@ class AccountPageState extends State<AccountPage> {
final theme = Theme.of(context); final theme = Theme.of(context);
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final cilState = context.watch<ContactInvitationListCubit>().state; final cilState = context.watch<ContactInvitationListCubit>().state;
final cilBusy = cilState.busy; final cilBusy = cilState.busy;
@ -55,10 +56,12 @@ class AccountPageState extends State<AccountPage> {
backgroundColor: scale.primaryScale.border, backgroundColor: scale.primaryScale.border,
collapsedBackgroundColor: scale.primaryScale.border, collapsedBackgroundColor: scale.primaryScale.border,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
), ),
collapsedShape: RoundedRectangleBorder( collapsedShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
), ),
title: Text( title: Text(
translate('account_page.contact_invitations'), translate('account_page.contact_invitations'),

View File

@ -1,12 +1,14 @@
import 'dart:async'; 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/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_translate/flutter_translate.dart'; import 'package:flutter_translate/flutter_translate.dart';
import 'package:preload_page_view/preload_page_view.dart'; import 'package:preload_page_view/preload_page_view.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
import '../../../../chat/chat.dart'; import '../../../../chat/chat.dart';
import '../../../../contact_invitation/contact_invitation.dart'; import '../../../../contact_invitation/contact_invitation.dart';
@ -39,7 +41,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
super.dispose(); super.dispose();
} }
bool onScrollNotification(ScrollNotification notification) { bool _onScrollNotification(ScrollNotification notification) {
if (notification is UserScrollNotification && if (notification is UserScrollNotification &&
notification.metrics.axis == Axis.vertical) { notification.metrics.axis == Axis.vertical) {
switch (notification.direction) { switch (notification.direction) {
@ -58,30 +60,6 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
return false; 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 { Future<void> scanContactInvitationDialog(BuildContext context) async {
await showDialog<void>( await showDialog<void>(
context: context, 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) { Widget _bottomSheetBuilder(BuildContext sheetContext, BuildContext context) {
if (currentPage == 0) { if (currentPage == 0) {
// New contact invitation // New contact invitation
@ -122,12 +157,13 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return Scaffold( return Scaffold(
//extendBody: true, //extendBody: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
body: NotificationListener<ScrollNotification>( body: NotificationListener<ScrollNotification>(
onNotification: onScrollNotification, onNotification: _onScrollNotification,
child: PreloadPageView( child: PreloadPageView(
key: _pageViewKey, key: _pageViewKey,
controller: pageController, controller: pageController,
@ -148,31 +184,46 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
// style: Theme.of(context).textTheme.headlineSmall, // style: Theme.of(context).textTheme.headlineSmall,
// ), // ),
// ), // ),
bottomNavigationBar: StylishBottomBar( bottomNavigationBar: AnimatedBottomNavigationBar.builder(
backgroundColor: scale.primaryScale.hoverBorder, itemCount: 2,
option: AnimatedBarOptions( height: 64,
inkEffect: true, tabBuilder: _buildBottomBarItem,
inkColor: scale.primaryScale.hoverPrimary, activeIndex: currentPage,
opacity: 0.3, gapLocation: GapLocation.end,
), gapWidth: 90,
items: _buildBottomBarItems(), notchSmoothness: NotchSmoothness.defaultEdge,
hasNotch: true, notchMargin: 4,
fabLocation: StylishBarFabLocation.end, backgroundColor: scaleConfig.preferBorders
currentIndex: currentPage, ? scale.primaryScale.hoverElementBackground
: scale.primaryScale.hoverBorder,
elevation: 0,
onTap: (index) async { onTap: (index) async {
await pageController.animateToPage(index, await pageController.animateToPage(index,
duration: 250.ms, curve: Curves.easeInOut); duration: 250.ms, curve: Curves.easeInOut);
}, },
), ),
floatingActionButton: BottomSheetActionButton( floatingActionButton: BottomSheetActionButton(
shape: const RoundedRectangleBorder( shape: CircleBorder(
borderRadius: BorderRadius.all(Radius.circular(14))), side: !scaleConfig.useVisualIndicators
foregroundColor: scale.secondaryScale.borderText, ? BorderSide.none
backgroundColor: scale.secondaryScale.hoverBorder, : 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( builder: (context) => Icon(
_fabIconList[currentPage], _fabIconList[currentPage],
color: scale.secondaryScale.borderText, color: scaleConfig.preferBorders
? scale.secondaryScale.border
: scale.secondaryScale.borderText,
), ),
bottomSheetBuilder: (sheetContext) => bottomSheetBuilder: (sheetContext) =>
_bottomSheetBuilder(sheetContext, context)), _bottomSheetBuilder(sheetContext, context)),

View File

@ -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) { Widget _buildAccountPageView(BuildContext context) {
final localAccounts = context.watch<LocalAccountsCubit>().state; final localAccounts = context.watch<LocalAccountsCubit>().state;
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state; final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
@ -127,7 +144,7 @@ class HomeScreenState extends State<HomeScreen>
final activeIndex = localAccounts final activeIndex = localAccounts
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount); .indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
if (activeIndex == -1) { if (activeIndex == -1) {
return const HomeNoActive(); return _applyPageBorder(const HomeNoActive());
} }
final accountPages = <Widget>[]; final accountPages = <Widget>[];
@ -141,7 +158,7 @@ class HomeScreenState extends State<HomeScreen>
} }
final accountPage = _buildAccountPage( final accountPage = _buildAccountPage(
context, superIdentityRecordKey, perAccountCollectionState); context, superIdentityRecordKey, perAccountCollectionState);
accountPages.add(KeyedSubtree.wrap(accountPage, i)); accountPages.add(_applyPageBorder(accountPage));
} }
return SlideIndexedStack( return SlideIndexedStack(
@ -154,15 +171,6 @@ class HomeScreenState extends State<HomeScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(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 localAccounts = context.watch<LocalAccountsCubit>().state;
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state; final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
@ -171,8 +179,8 @@ class HomeScreenState extends State<HomeScreen>
final canClose = activeIndex != -1; final canClose = activeIndex != -1;
return SafeArea( return SafeArea(
child: DecoratedBox( child: DefaultTextStyle(
decoration: BoxDecoration(gradient: gradient), style: theme.textTheme.bodySmall!,
child: ZoomDrawer( child: ZoomDrawer(
controller: _zoomDrawerController, controller: _zoomDrawerController,
//menuBackgroundColor: Colors.transparent, //menuBackgroundColor: Colors.transparent,
@ -188,18 +196,16 @@ class HomeScreenState extends State<HomeScreen>
mainScreen: Provider<ZoomDrawerController>.value( mainScreen: Provider<ZoomDrawerController>.value(
value: _zoomDrawerController, value: _zoomDrawerController,
child: Builder(builder: _buildAccountPageView)), child: Builder(builder: _buildAccountPageView)),
borderRadius: 24, borderRadius: 0,
//showShadow: false,
angle: 0, angle: 0,
drawerShadowsBackgroundColor: theme.shadowColor, mainScreenOverlayColor: theme.shadowColor.withAlpha(0x2F),
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x3F),
openCurve: Curves.fastEaseInToSlowEaseOut, openCurve: Curves.fastEaseInToSlowEaseOut,
// duration: const Duration(milliseconds: 250), // duration: const Duration(milliseconds: 250),
// reverseDuration: const Duration(milliseconds: 250), // reverseDuration: const Duration(milliseconds: 250),
menuScreenTapClose: canClose, menuScreenTapClose: canClose,
mainScreenTapClose: canClose, mainScreenTapClose: canClose,
disableDragGesture: !canClose, disableDragGesture: !canClose,
mainScreenScale: .25, mainScreenScale: .15,
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9), slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
))); )));
} }

View File

@ -36,19 +36,18 @@ class SettingsPageState extends State<SettingsPage> {
@override @override
Widget build(BuildContext context) => Widget build(BuildContext context) =>
AsyncBlocBuilder<PreferencesCubit, Preferences>( AsyncBlocBuilder<PreferencesCubit, Preferences>(
builder: (context, state) => ThemeSwitchingArea( builder: (context, state) => StyledScaffold(
child: Scaffold( appBar: DefaultAppBar(
appBar: DefaultAppBar( title: Text(translate('settings_page.titlebar')),
title: Text(translate('settings_page.titlebar')), leading: IconButton(
leading: IconButton( icon: const Icon(Icons.arrow_back),
icon: const Icon(Icons.arrow_back), onPressed: () => GoRouterHelper(context).pop(),
onPressed: () => GoRouterHelper(context).pop(), ),
), actions: <Widget>[
actions: <Widget>[ const SignalStrengthMeterWidget().paddingLTRB(16, 0, 16, 0),
const SignalStrengthMeterWidget() ]),
.paddingLTRB(16, 0, 16, 0), body: ThemeSwitchingArea(
]), child: FormBuilder(
body: FormBuilder(
key: _formKey, key: _formKey,
child: ListView( child: ListView(
children: [ children: [

View File

@ -5,47 +5,82 @@ import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'scale_scheme.dart'; import 'scale_scheme.dart';
ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) => ChatTheme makeChatTheme(
ScaleScheme scale, ScaleConfig scaleConfig, TextTheme textTheme) =>
DefaultChatTheme( DefaultChatTheme(
primaryColor: scale.primaryScale.calloutBackground, primaryColor: scaleConfig.preferBorders
secondaryColor: scale.secondaryScale.calloutBackground, ? scale.primaryScale.calloutText
: scale.primaryScale.calloutBackground,
secondaryColor: scaleConfig.preferBorders
? scale.secondaryScale.calloutText
: scale.secondaryScale.calloutBackground,
backgroundColor: scale.grayScale.appBackground, backgroundColor: scale.grayScale.appBackground,
messageBorderRadius: scaleConfig.borderRadiusScale * 16,
bubbleBorderSide: scaleConfig.preferBorders
? BorderSide(
color: scale.primaryScale.calloutBackground,
width: 2,
)
: null,
sendButtonIcon: Image.asset( sendButtonIcon: Image.asset(
'assets/icon-send.png', 'assets/icon-send.png',
color: scale.primaryScale.borderText, color: scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText,
package: 'flutter_chat_ui', package: 'flutter_chat_ui',
), ),
inputBackgroundColor: Colors.blue, inputBackgroundColor: Colors.blue,
inputBorderRadius: BorderRadius.zero, inputBorderRadius: BorderRadius.zero,
inputTextDecoration: InputDecoration( inputTextDecoration: InputDecoration(
filled: true, filled: !scaleConfig.preferBorders,
fillColor: scale.primaryScale.elementBackground, fillColor: scale.primaryScale.subtleBackground,
isDense: true, isDense: true,
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12), contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
border: const OutlineInputBorder( disabledBorder: OutlineInputBorder(
borderSide: BorderSide.none, borderSide: scaleConfig.preferBorders
borderRadius: BorderRadius.all(Radius.circular(8))), ? BorderSide(color: scale.grayScale.border, width: 2)
focusedBorder: const OutlineInputBorder( : BorderSide.none,
borderSide: BorderSide.none, borderRadius: BorderRadius.all(
borderRadius: BorderRadius.all(Radius.circular(8))), Radius.circular(8 * scaleConfig.borderRadiusScale))),
enabledBorder: OutlineInputBorder(
borderSide: scaleConfig.preferBorders
? BorderSide(color: scale.primaryScale.border, width: 2)
: BorderSide.none,
borderRadius: BorderRadius.all(
Radius.circular(8 * scaleConfig.borderRadiusScale))),
focusedBorder: OutlineInputBorder(
borderSide: scaleConfig.preferBorders
? BorderSide(color: scale.primaryScale.border, width: 2)
: BorderSide.none,
borderRadius: BorderRadius.all(
Radius.circular(8 * scaleConfig.borderRadiusScale))),
), ),
inputContainerDecoration: inputContainerDecoration: BoxDecoration(
BoxDecoration(color: scale.primaryScale.border), border: scaleConfig.preferBorders
inputPadding: const EdgeInsets.all(9), ? Border(
inputTextColor: scale.primaryScale.appText, top: BorderSide(color: scale.primaryScale.border, width: 2))
: null,
color: scaleConfig.preferBorders
? scale.primaryScale.elementBackground
: scale.primaryScale.border),
inputPadding: const EdgeInsets.all(12),
inputTextColor: !scaleConfig.preferBorders
? scale.primaryScale.appText
: scale.primaryScale.border,
attachmentButtonIcon: const Icon(Icons.attach_file), attachmentButtonIcon: const Icon(Icons.attach_file),
sentMessageBodyTextStyle: TextStyle( sentMessageBodyTextStyle: textTheme.bodyLarge!.copyWith(
color: scale.primaryScale.calloutText, color: scaleConfig.preferBorders
fontSize: 16, ? scale.primaryScale.calloutBackground
fontWeight: FontWeight.w500, : scale.primaryScale.calloutText,
height: 1.5,
), ),
sentEmojiMessageTextStyle: const TextStyle( sentEmojiMessageTextStyle: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 64, fontSize: 64,
), ),
receivedMessageBodyTextStyle: TextStyle( receivedMessageBodyTextStyle: TextStyle(
color: scale.secondaryScale.calloutText, color: scaleConfig.preferBorders
? scale.secondaryScale.calloutBackground
: scale.secondaryScale.calloutText,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
height: 1.5, height: 1.5,

View File

@ -5,11 +5,14 @@ import 'scale_color.dart';
import 'scale_input_decorator_theme.dart'; import 'scale_input_decorator_theme.dart';
import 'scale_scheme.dart'; import 'scale_scheme.dart';
ScaleScheme _contrastScale(Brightness brightness) { ScaleColor _contrastScaleColor(
final back = brightness == Brightness.light ? Colors.white : Colors.black; {required Brightness brightness,
final front = brightness == Brightness.light ? Colors.black : Colors.white; required Color frontColor,
required Color backColor}) {
final back = brightness == Brightness.light ? backColor : frontColor;
final front = brightness == Brightness.light ? frontColor : backColor;
final primaryScale = ScaleColor( return ScaleColor(
appBackground: back, appBackground: back,
subtleBackground: back, subtleBackground: back,
elementBackground: back, elementBackground: back,
@ -28,21 +31,236 @@ ScaleScheme _contrastScale(Brightness brightness) {
calloutBackground: front, calloutBackground: front,
calloutText: back, calloutText: back,
); );
return ScaleScheme(
primaryScale: primaryScale,
primaryAlphaScale: primaryScale,
secondaryScale: primaryScale,
tertiaryScale: primaryScale,
grayScale: primaryScale,
errorScale: primaryScale);
} }
ThemeData contrastGenerator(Brightness brightness) { const kMonoSpaceFontDisplay = 'Source Code Pro';
final textTheme = makeRadixTextTheme(brightness); const kMonoSpaceFontText = 'Source Code Pro';
final scaleScheme = _contrastScale(brightness);
final colorScheme = scaleScheme.toColorScheme(brightness); TextTheme makeMonoSpaceTextTheme(Brightness brightness) =>
final scaleConfig = ScaleConfig(useVisualIndicators: true); (brightness == Brightness.light)
? const TextTheme(
displayLarge: TextStyle(
debugLabel: 'blackMonoSpace displayLarge',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black54,
decoration: TextDecoration.none),
displayMedium: TextStyle(
debugLabel: 'blackMonoSpace displayMedium',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black54,
decoration: TextDecoration.none),
displaySmall: TextStyle(
debugLabel: 'blackMonoSpace displaySmall',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black54,
decoration: TextDecoration.none),
headlineLarge: TextStyle(
debugLabel: 'blackMonoSpace headlineLarge',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black54,
decoration: TextDecoration.none),
headlineMedium: TextStyle(
debugLabel: 'blackMonoSpace headlineMedium',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black54,
decoration: TextDecoration.none),
headlineSmall: TextStyle(
debugLabel: 'blackMonoSpace headlineSmall',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black87,
decoration: TextDecoration.none),
titleLarge: TextStyle(
debugLabel: 'blackMonoSpace titleLarge',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.black87,
decoration: TextDecoration.none),
titleMedium: TextStyle(
debugLabel: 'blackMonoSpace titleMedium',
fontFamily: kMonoSpaceFontText,
color: Colors.black87,
decoration: TextDecoration.none),
titleSmall: TextStyle(
debugLabel: 'blackMonoSpace titleSmall',
fontFamily: kMonoSpaceFontText,
color: Colors.black,
decoration: TextDecoration.none),
bodyLarge: TextStyle(
debugLabel: 'blackMonoSpace bodyLarge',
fontFamily: kMonoSpaceFontText,
color: Colors.black87,
decoration: TextDecoration.none),
bodyMedium: TextStyle(
debugLabel: 'blackMonoSpace bodyMedium',
fontFamily: kMonoSpaceFontText,
color: Colors.black87,
decoration: TextDecoration.none),
bodySmall: TextStyle(
debugLabel: 'blackMonoSpace bodySmall',
fontFamily: kMonoSpaceFontText,
color: Colors.black54,
decoration: TextDecoration.none),
labelLarge: TextStyle(
debugLabel: 'blackMonoSpace labelLarge',
fontFamily: kMonoSpaceFontText,
color: Colors.black87,
decoration: TextDecoration.none),
labelMedium: TextStyle(
debugLabel: 'blackMonoSpace labelMedium',
fontFamily: kMonoSpaceFontText,
color: Colors.black,
decoration: TextDecoration.none),
labelSmall: TextStyle(
debugLabel: 'blackMonoSpace labelSmall',
fontFamily: kMonoSpaceFontText,
color: Colors.black,
decoration: TextDecoration.none),
)
: const TextTheme(
displayLarge: TextStyle(
debugLabel: 'whiteMonoSpace displayLarge',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white70,
decoration: TextDecoration.none),
displayMedium: TextStyle(
debugLabel: 'whiteMonoSpace displayMedium',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white70,
decoration: TextDecoration.none),
displaySmall: TextStyle(
debugLabel: 'whiteMonoSpace displaySmall',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white70,
decoration: TextDecoration.none),
headlineLarge: TextStyle(
debugLabel: 'whiteMonoSpace headlineLarge',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white70,
decoration: TextDecoration.none),
headlineMedium: TextStyle(
debugLabel: 'whiteMonoSpace headlineMedium',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white70,
decoration: TextDecoration.none),
headlineSmall: TextStyle(
debugLabel: 'whiteMonoSpace headlineSmall',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white,
decoration: TextDecoration.none),
titleLarge: TextStyle(
debugLabel: 'whiteMonoSpace titleLarge',
fontFamily: kMonoSpaceFontDisplay,
color: Colors.white,
decoration: TextDecoration.none),
titleMedium: TextStyle(
debugLabel: 'whiteMonoSpace titleMedium',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
titleSmall: TextStyle(
debugLabel: 'whiteMonoSpace titleSmall',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
bodyLarge: TextStyle(
debugLabel: 'whiteMonoSpace bodyLarge',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
bodyMedium: TextStyle(
debugLabel: 'whiteMonoSpace bodyMedium',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
bodySmall: TextStyle(
debugLabel: 'whiteMonoSpace bodySmall',
fontFamily: kMonoSpaceFontText,
color: Colors.white70,
decoration: TextDecoration.none),
labelLarge: TextStyle(
debugLabel: 'whiteMonoSpace labelLarge',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
labelMedium: TextStyle(
debugLabel: 'whiteMonoSpace labelMedium',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
labelSmall: TextStyle(
debugLabel: 'whiteMonoSpace labelSmall',
fontFamily: kMonoSpaceFontText,
color: Colors.white,
decoration: TextDecoration.none),
);
ScaleScheme _contrastScaleScheme(
{required Brightness brightness,
required Color primaryFront,
required Color primaryBack,
required Color secondaryFront,
required Color secondaryBack,
required Color tertiaryFront,
required Color tertiaryBack,
required Color grayFront,
required Color grayBack,
required Color errorFront,
required Color errorBack}) =>
ScaleScheme(
primaryScale: _contrastScaleColor(
brightness: brightness,
frontColor: primaryFront,
backColor: primaryBack),
primaryAlphaScale: _contrastScaleColor(
brightness: brightness,
frontColor: primaryFront,
backColor: primaryBack),
secondaryScale: _contrastScaleColor(
brightness: brightness,
frontColor: secondaryFront,
backColor: secondaryBack),
tertiaryScale: _contrastScaleColor(
brightness: brightness,
frontColor: tertiaryFront,
backColor: tertiaryBack),
grayScale: _contrastScaleColor(
brightness: brightness, frontColor: grayFront, backColor: grayBack),
errorScale: _contrastScaleColor(
brightness: brightness,
frontColor: errorFront,
backColor: errorBack));
ThemeData contrastGenerator({
required Brightness brightness,
required ScaleConfig scaleConfig,
required Color primaryFront,
required Color primaryBack,
required Color secondaryFront,
required Color secondaryBack,
required Color tertiaryFront,
required Color tertiaryBack,
required Color grayFront,
required Color grayBack,
required Color errorFront,
required Color errorBack,
TextTheme? customTextTheme,
}) {
final textTheme = customTextTheme ?? makeRadixTextTheme(brightness);
final scaleScheme = _contrastScaleScheme(
brightness: brightness,
primaryFront: primaryFront,
primaryBack: primaryBack,
secondaryFront: secondaryFront,
secondaryBack: secondaryBack,
tertiaryFront: tertiaryFront,
tertiaryBack: tertiaryBack,
grayFront: grayFront,
grayBack: grayBack,
errorFront: errorFront,
errorBack: errorBack,
);
final colorScheme = scaleScheme.toColorScheme(
brightness,
);
final themeData = ThemeData.from( final themeData = ThemeData.from(
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true); colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
@ -50,10 +268,11 @@ ThemeData contrastGenerator(Brightness brightness) {
bottomSheetTheme: themeData.bottomSheetTheme.copyWith( bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
elevation: 0, elevation: 0,
modalElevation: 0, modalElevation: 0,
shape: const RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16), topLeft: Radius.circular(16 * scaleConfig.borderRadiusScale),
topRight: Radius.circular(16)))), topRight:
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
canvasColor: scaleScheme.primaryScale.subtleBackground, canvasColor: scaleScheme.primaryScale.subtleBackground,
chipTheme: themeData.chipTheme.copyWith( chipTheme: themeData.chipTheme.copyWith(
backgroundColor: scaleScheme.primaryScale.elementBackground, backgroundColor: scaleScheme.primaryScale.elementBackground,
@ -69,13 +288,15 @@ ThemeData contrastGenerator(Brightness brightness) {
disabledForegroundColor: scaleScheme.grayScale.appText, disabledForegroundColor: scaleScheme.grayScale.appText,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide(color: scaleScheme.primaryScale.border), side: BorderSide(color: scaleScheme.primaryScale.border),
borderRadius: BorderRadius.circular(8))), borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale))),
), ),
textSelectionTheme: TextSelectionThemeData( textSelectionTheme: TextSelectionThemeData(
cursorColor: scaleScheme.primaryScale.appText, cursorColor: scaleScheme.primaryScale.appText,
selectionColor: scaleScheme.primaryScale.appText.withAlpha(0x7F), selectionColor: scaleScheme.primaryScale.appText.withAlpha(0x7F),
selectionHandleColor: scaleScheme.primaryScale.appText), selectionHandleColor: scaleScheme.primaryScale.appText),
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme), inputDecorationTheme:
ScaleInputDecoratorTheme(scaleScheme, scaleConfig, textTheme),
extensions: <ThemeExtension<dynamic>>[ extensions: <ThemeExtension<dynamic>>[
scaleScheme, scaleScheme,
scaleConfig, scaleConfig,

View File

@ -604,7 +604,11 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
final radix = _radixScheme(brightness, themeColor); final radix = _radixScheme(brightness, themeColor);
final scaleScheme = radix.toScale(); final scaleScheme = radix.toScale();
final colorScheme = scaleScheme.toColorScheme(brightness); final colorScheme = scaleScheme.toColorScheme(brightness);
final scaleConfig = ScaleConfig(useVisualIndicators: false); final scaleConfig = ScaleConfig(
useVisualIndicators: false,
preferBorders: false,
borderRadiusScale: 1,
);
final themeData = ThemeData.from( final themeData = ThemeData.from(
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true); colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
@ -654,8 +658,10 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
disabledForegroundColor: scaleScheme.grayScale.primary, disabledForegroundColor: scaleScheme.grayScale.primary,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide(color: scaleScheme.primaryScale.border), side: BorderSide(color: scaleScheme.primaryScale.border),
borderRadius: BorderRadius.circular(8))), borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale))),
), ),
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme), inputDecorationTheme:
ScaleInputDecoratorTheme(scaleScheme, scaleConfig, textTheme),
extensions: <ThemeExtension<dynamic>>[scaleScheme, scaleConfig]); extensions: <ThemeExtension<dynamic>>[scaleScheme, scaleConfig]);
} }

View File

@ -3,11 +3,13 @@ import 'package:flutter/material.dart';
import 'scale_scheme.dart'; import 'scale_scheme.dart';
class ScaleInputDecoratorTheme extends InputDecorationTheme { class ScaleInputDecoratorTheme extends InputDecorationTheme {
ScaleInputDecoratorTheme(this._scaleScheme, this._textTheme) ScaleInputDecoratorTheme(
this._scaleScheme, ScaleConfig scaleConfig, this._textTheme)
: super( : super(
border: OutlineInputBorder( border: OutlineInputBorder(
borderSide: BorderSide(color: _scaleScheme.primaryScale.border), borderSide: BorderSide(color: _scaleScheme.primaryScale.border),
borderRadius: BorderRadius.circular(8)), borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale)),
contentPadding: const EdgeInsets.all(8), contentPadding: const EdgeInsets.all(8),
labelStyle: TextStyle( labelStyle: TextStyle(
color: _scaleScheme.primaryScale.subtleText.withAlpha(127)), color: _scaleScheme.primaryScale.subtleText.withAlpha(127)),
@ -16,7 +18,8 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: _scaleScheme.primaryScale.hoverBorder, width: 2), color: _scaleScheme.primaryScale.hoverBorder, width: 2),
borderRadius: BorderRadius.circular(8))); borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale)));
final ScaleScheme _scaleScheme; final ScaleScheme _scaleScheme;
final TextTheme _textTheme; final TextTheme _textTheme;

View File

@ -1,3 +1,6 @@
import 'dart:ui';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'scale_color.dart'; import 'scale_color.dart';
@ -97,7 +100,7 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
onSurfaceVariant: secondaryScale.primaryText, // ?? reviewed a little onSurfaceVariant: secondaryScale.primaryText, // ?? reviewed a little
outline: primaryScale.border, outline: primaryScale.border,
outlineVariant: secondaryScale.border, outlineVariant: secondaryScale.border,
shadow: const Color(0xFF000000), shadow: primaryScale.primary.darken(80),
//scrim: primaryScale.background, //scrim: primaryScale.background,
// inverseSurface: primaryScale.subtleText, // inverseSurface: primaryScale.subtleText,
// onInverseSurface: primaryScale.subtleBackground, // onInverseSurface: primaryScale.subtleBackground,
@ -109,16 +112,24 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
class ScaleConfig extends ThemeExtension<ScaleConfig> { class ScaleConfig extends ThemeExtension<ScaleConfig> {
ScaleConfig({ ScaleConfig({
required this.useVisualIndicators, required this.useVisualIndicators,
required this.preferBorders,
required this.borderRadiusScale,
}); });
final bool useVisualIndicators; final bool useVisualIndicators;
final bool preferBorders;
final double borderRadiusScale;
@override @override
ScaleConfig copyWith({ ScaleConfig copyWith({
bool? useVisualIndicators, bool? useVisualIndicators,
bool? preferBorders,
double? borderRadiusScale,
}) => }) =>
ScaleConfig( ScaleConfig(
useVisualIndicators: useVisualIndicators ?? this.useVisualIndicators, useVisualIndicators: useVisualIndicators ?? this.useVisualIndicators,
preferBorders: preferBorders ?? this.preferBorders,
borderRadiusScale: borderRadiusScale ?? this.borderRadiusScale,
); );
@override @override
@ -127,8 +138,10 @@ class ScaleConfig extends ThemeExtension<ScaleConfig> {
return this; return this;
} }
return ScaleConfig( return ScaleConfig(
useVisualIndicators: useVisualIndicators:
t < .5 ? useVisualIndicators : other.useVisualIndicators, t < .5 ? useVisualIndicators : other.useVisualIndicators,
); preferBorders: t < .5 ? preferBorders : other.preferBorders,
borderRadiusScale:
lerpDouble(borderRadiusScale, other.borderRadiusScale, t) ?? 1);
} }
} }

View File

@ -64,13 +64,13 @@ class SliderTile extends StatelessWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final tileColor = scale.scale(!disabled ? tileScale : ScaleKind.gray); final tileColor = scale.scale(!disabled ? tileScale : ScaleKind.gray);
final scalecfg = theme.extension<ScaleConfig>()!; final scaleConfig = theme.extension<ScaleConfig>()!;
final borderColor = selected ? tileColor.hoverBorder : tileColor.border; final borderColor = selected ? tileColor.hoverBorder : tileColor.border;
final backgroundColor = scalecfg.useVisualIndicators && !selected final backgroundColor = scaleConfig.useVisualIndicators && !selected
? tileColor.borderText ? tileColor.borderText
: borderColor; : borderColor;
final textColor = scalecfg.useVisualIndicators && !selected final textColor = scaleConfig.useVisualIndicators && !selected
? borderColor ? borderColor
: tileColor.borderText; : tileColor.borderText;
@ -79,10 +79,11 @@ class SliderTile extends StatelessWidget {
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: backgroundColor, color: backgroundColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: scalecfg.useVisualIndicators side: scaleConfig.useVisualIndicators
? BorderSide(width: 2, color: borderColor, strokeAlign: 0) ? BorderSide(width: 2, color: borderColor, strokeAlign: 0)
: BorderSide.none, : BorderSide.none,
borderRadius: BorderRadius.circular(8), borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
)), )),
child: Slidable( child: Slidable(
// Specify a key if the Slidable is dismissible. // Specify a key if the Slidable is dismissible.
@ -95,12 +96,12 @@ class SliderTile extends StatelessWidget {
.map( .map(
(a) => SlidableAction( (a) => SlidableAction(
onPressed: disabled ? null : a.onPressed, onPressed: disabled ? null : a.onPressed,
backgroundColor: scalecfg.useVisualIndicators backgroundColor: scaleConfig.useVisualIndicators
? (selected ? (selected
? tileColor.borderText ? tileColor.borderText
: tileColor.border) : tileColor.border)
: scale.scale(a.actionScale).primary, : scale.scale(a.actionScale).primary,
foregroundColor: scalecfg.useVisualIndicators foregroundColor: scaleConfig.useVisualIndicators
? (selected ? (selected
? tileColor.border ? tileColor.border
: tileColor.borderText) : tileColor.borderText)
@ -118,12 +119,12 @@ class SliderTile extends StatelessWidget {
.map( .map(
(a) => SlidableAction( (a) => SlidableAction(
onPressed: disabled ? null : a.onPressed, onPressed: disabled ? null : a.onPressed,
backgroundColor: scalecfg.useVisualIndicators backgroundColor: scaleConfig.useVisualIndicators
? (selected ? (selected
? tileColor.borderText ? tileColor.borderText
: tileColor.border) : tileColor.border)
: scale.scale(a.actionScale).primary, : scale.scale(a.actionScale).primary,
foregroundColor: scalecfg.useVisualIndicators foregroundColor: scaleConfig.useVisualIndicators
? (selected ? (selected
? tileColor.border ? tileColor.border
: tileColor.borderText) : tileColor.borderText)
@ -134,7 +135,7 @@ class SliderTile extends StatelessWidget {
) )
.toList()), .toList()),
child: Padding( child: Padding(
padding: scalecfg.useVisualIndicators padding: scaleConfig.useVisualIndicators
? EdgeInsets.zero ? EdgeInsets.zero
: const EdgeInsets.fromLTRB(0, 2, 0, 2), : const EdgeInsets.fromLTRB(0, 2, 0, 2),
child: ListTile( child: ListTile(

View File

@ -5,6 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../views/widget_helpers.dart'; import '../views/widget_helpers.dart';
import 'contrast_generator.dart'; import 'contrast_generator.dart';
import 'radix_generator.dart'; import 'radix_generator.dart';
import 'scale_scheme.dart';
part 'theme_preference.freezed.dart'; part 'theme_preference.freezed.dart';
part 'theme_preference.g.dart'; part 'theme_preference.g.dart';
@ -37,6 +38,7 @@ enum ColorPreference {
lime, lime,
grim, grim,
// Accessible Colors // Accessible Colors
elite,
contrast; contrast;
factory ColorPreference.fromJson(dynamic j) => factory ColorPreference.fromJson(dynamic j) =>
@ -63,7 +65,7 @@ class ThemePreferences with _$ThemePreferences {
} }
extension ThemePreferencesExt on ThemePreferences { extension ThemePreferencesExt on ThemePreferences {
/// Get material 'ThemeData' for existinb /// Get material 'ThemeData' for existing theme
ThemeData themeData() { ThemeData themeData() {
late final Brightness brightness; late final Brightness brightness;
switch (brightnessPreference) { switch (brightnessPreference) {
@ -83,8 +85,60 @@ extension ThemePreferencesExt on ThemePreferences {
switch (colorPreference) { switch (colorPreference) {
// Special cases // Special cases
case ColorPreference.contrast: case ColorPreference.contrast:
// xxx do contrastGenerator themeData = contrastGenerator(
themeData = contrastGenerator(brightness); brightness: brightness,
scaleConfig: ScaleConfig(
useVisualIndicators: true,
preferBorders: false,
borderRadiusScale: 1),
primaryFront: Colors.black,
primaryBack: Colors.white,
secondaryFront: Colors.black,
secondaryBack: Colors.white,
tertiaryFront: Colors.black,
tertiaryBack: Colors.white,
grayFront: Colors.black,
grayBack: Colors.white,
errorFront: Colors.black,
errorBack: Colors.white,
);
case ColorPreference.elite:
themeData = brightness == Brightness.light
? contrastGenerator(
brightness: Brightness.light,
scaleConfig: ScaleConfig(
useVisualIndicators: true,
preferBorders: true,
borderRadiusScale: 0.2),
primaryFront: const Color(0xFF000000),
primaryBack: const Color(0xFF00FF00),
secondaryFront: const Color(0xFF000000),
secondaryBack: const Color(0xFF00FFFF),
tertiaryFront: const Color(0xFF000000),
tertiaryBack: const Color(0xFFFF00FF),
grayFront: const Color(0xFF000000),
grayBack: const Color(0xFFFFFFFF),
errorFront: const Color(0xFFC0C0C0),
errorBack: const Color(0xFF0000FF),
customTextTheme: makeMonoSpaceTextTheme(Brightness.light))
: contrastGenerator(
brightness: Brightness.dark,
scaleConfig: ScaleConfig(
useVisualIndicators: true,
preferBorders: true,
borderRadiusScale: 0.5),
primaryFront: const Color(0xFF000000),
primaryBack: const Color(0xFF00FF00),
secondaryFront: const Color(0xFF000000),
secondaryBack: const Color(0xFF00FFFF),
tertiaryFront: const Color(0xFF000000),
tertiaryBack: const Color(0xFFFF00FF),
grayFront: const Color(0xFF000000),
grayBack: const Color(0xFFFFFFFF),
errorFront: const Color(0xFF0000FF),
errorBack: const Color(0xFFC0C0C0),
customTextTheme: makeMonoSpaceTextTheme(Brightness.dark),
);
// Generate from Radix // Generate from Radix
case ColorPreference.scarlet: case ColorPreference.scarlet:
themeData = radixGenerator(brightness, RadixThemeColor.scarlet); themeData = radixGenerator(brightness, RadixThemeColor.scarlet);

View File

@ -22,6 +22,7 @@ List<DropdownMenuItem<dynamic>> _getThemeDropdownItems() {
ColorPreference.eggplant: translate('themes.eggplant'), ColorPreference.eggplant: translate('themes.eggplant'),
ColorPreference.lime: translate('themes.lime'), ColorPreference.lime: translate('themes.lime'),
ColorPreference.grim: translate('themes.grim'), ColorPreference.grim: translate('themes.grim'),
ColorPreference.elite: translate('themes.elite'),
ColorPreference.contrast: translate('themes.contrast') ColorPreference.contrast: translate('themes.contrast')
}; };

View File

@ -11,12 +11,14 @@ class StyledDialog extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
return AlertDialog( return AlertDialog(
elevation: 0, elevation: 0,
shape: const RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16)), borderRadius: BorderRadius.all(
Radius.circular(16 * scaleConfig.borderRadiusScale)),
), ),
contentPadding: const EdgeInsets.all(4), contentPadding: const EdgeInsets.all(4),
backgroundColor: scale.primaryScale.dialogBorder, backgroundColor: scale.primaryScale.dialogBorder,
@ -31,12 +33,14 @@ class StyledDialog extends StatelessWidget {
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: scale.primaryScale.border, color: scale.primaryScale.border,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16))), borderRadius: BorderRadius.circular(
16 * scaleConfig.borderRadiusScale))),
child: DecoratedBox( child: DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: scale.primaryScale.appBackground, color: scale.primaryScale.appBackground,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12))), borderRadius: BorderRadius.circular(
12 * scaleConfig.borderRadiusScale))),
child: child.paddingAll(0)))); child: child.paddingAll(0))));
} }

View File

@ -0,0 +1,27 @@
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart';
import '../theme.dart';
class StyledScaffold extends StatelessWidget {
const StyledScaffold({required this.appBar, required this.body, super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return clipBorder(
clipEnabled: true,
borderEnabled: scaleConfig.useVisualIndicators,
borderRadius: 16 * scaleConfig.borderRadiusScale,
borderColor: scale.primaryScale.border,
child: Scaffold(appBar: appBar, body: body, key: key))
.paddingAll(32);
}
////////////////////////////////////////////////////////////////////////////
final PreferredSizeWidget? appBar;
final Widget? body;
}

View File

@ -2,4 +2,5 @@ export 'brightness_preferences.dart';
export 'color_preferences.dart'; export 'color_preferences.dart';
export 'scanner_error_widget.dart'; export 'scanner_error_widget.dart';
export 'styled_dialog.dart'; export 'styled_dialog.dart';
export 'styled_scaffold.dart';
export 'widget_helpers.dart'; export 'widget_helpers.dart';

View File

@ -132,7 +132,7 @@ void showErrorToast(BuildContext context, String message) {
contentPadding: const EdgeInsets.all(16), contentPadding: const EdgeInsets.all(16),
primaryColor: scale.errorScale.elementBackground, primaryColor: scale.errorScale.elementBackground,
secondaryColor: scale.errorScale.calloutBackground, secondaryColor: scale.errorScale.calloutBackground,
borderRadius: 16, borderRadius: 16 * scaleConfig.borderRadiusScale,
toastDuration: const Duration(seconds: 4), toastDuration: const Duration(seconds: 4),
animationDuration: const Duration(milliseconds: 1000), animationDuration: const Duration(milliseconds: 1000),
displayBorder: scaleConfig.useVisualIndicators, displayBorder: scaleConfig.useVisualIndicators,
@ -152,7 +152,7 @@ void showInfoToast(BuildContext context, String message) {
contentPadding: const EdgeInsets.all(16), contentPadding: const EdgeInsets.all(16),
primaryColor: scale.tertiaryScale.elementBackground, primaryColor: scale.tertiaryScale.elementBackground,
secondaryColor: scale.tertiaryScale.calloutBackground, secondaryColor: scale.tertiaryScale.calloutBackground,
borderRadius: 16, borderRadius: 16 * scaleConfig.borderRadiusScale,
toastDuration: const Duration(seconds: 2), toastDuration: const Duration(seconds: 2),
animationDuration: const Duration(milliseconds: 500), animationDuration: const Duration(milliseconds: 500),
displayBorder: scaleConfig.useVisualIndicators, displayBorder: scaleConfig.useVisualIndicators,
@ -170,13 +170,15 @@ Widget styledTitleContainer({
}) { }) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
return DecoratedBox( return DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: borderColor ?? scale.primaryScale.border, color: borderColor ?? scale.primaryScale.border,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
)), )),
child: Column(children: [ child: Column(children: [
Text( Text(
@ -189,7 +191,8 @@ Widget styledTitleContainer({
color: color:
backgroundColor ?? scale.primaryScale.subtleBackground, backgroundColor ?? scale.primaryScale.subtleBackground,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(
16 * scaleConfig.borderRadiusScale),
)), )),
child: child) child: child)
.paddingAll(4) .paddingAll(4)
@ -207,15 +210,17 @@ Widget styledBottomSheet({
}) { }) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
return DecoratedBox( return DecoratedBox(
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: borderColor ?? scale.primaryScale.dialogBorder, color: borderColor ?? scale.primaryScale.dialogBorder,
shape: const RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16), topLeft: Radius.circular(16 * scaleConfig.borderRadiusScale),
topRight: Radius.circular(16)))), topRight:
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
child: Column(mainAxisSize: MainAxisSize.min, children: [ child: Column(mainAxisSize: MainAxisSize.min, children: [
Text( Text(
title, title,
@ -226,10 +231,12 @@ Widget styledBottomSheet({
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: color:
backgroundColor ?? scale.primaryScale.subtleBackground, backgroundColor ?? scale.primaryScale.subtleBackground,
shape: const RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(16), topLeft: Radius.circular(
topRight: Radius.circular(16)))), 16 * scaleConfig.borderRadiusScale),
topRight: Radius.circular(
16 * scaleConfig.borderRadiusScale)))),
child: child) child: child)
.paddingLTRB(4, 4, 4, 0) .paddingLTRB(4, 4, 4, 0)
])); ]));
@ -261,3 +268,25 @@ const grayColorFilter = ColorFilter.matrix(<double>[
1, 1,
0, 0,
]); ]);
Widget clipBorder({
required bool clipEnabled,
required bool borderEnabled,
required double borderRadius,
required Color borderColor,
required Widget child,
}) =>
ClipRRect(
borderRadius: clipEnabled
? BorderRadius.circular(borderRadius)
: BorderRadius.zero,
child: DecoratedBox(
decoration: BoxDecoration(boxShadow: [
if (borderEnabled) BoxShadow(color: borderColor, spreadRadius: 2)
]),
child: ClipRRect(
borderRadius: clipEnabled
? BorderRadius.circular(borderRadius)
: BorderRadius.zero,
child: child,
)).paddingAll(clipEnabled && borderEnabled ? 2 : 0));

View File

@ -51,6 +51,7 @@ class _EnterPinDialogState extends State<EnterPinDialog> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final focusedBorderColor = scale.primaryScale.hoverBorder; final focusedBorderColor = scale.primaryScale.hoverBorder;
final fillColor = scale.primaryScale.elementBackground; final fillColor = scale.primaryScale.elementBackground;
final borderColor = scale.primaryScale.border; final borderColor = scale.primaryScale.border;
@ -61,7 +62,7 @@ class _EnterPinDialogState extends State<EnterPinDialog> {
textStyle: TextStyle(fontSize: 22, color: scale.primaryScale.appText), textStyle: TextStyle(fontSize: 22, color: scale.primaryScale.appText),
decoration: BoxDecoration( decoration: BoxDecoration(
color: fillColor, color: fillColor,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
border: Border.all(color: borderColor), border: Border.all(color: borderColor),
), ),
); );

View File

@ -140,6 +140,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
final theme = Theme.of(context); final theme = Theme.of(context);
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
// WidgetsBinding.instance.addPostFrameCallback((_) { // WidgetsBinding.instance.addPostFrameCallback((_) {
// if (!_isScrolling && _wantsBottom) { // if (!_isScrolling && _wantsBottom) {
@ -225,12 +226,22 @@ class _DeveloperPageState extends State<DeveloperPage> {
.copyWith(color: scale.primaryScale.primaryText), .copyWith(color: scale.primaryScale.primaryText),
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4), padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
openBoxDecoration: BoxDecoration( openBoxDecoration: BoxDecoration(
color: scale.primaryScale.border, //color: scale.primaryScale.border,
borderRadius: BorderRadius.circular(8), border: Border.all(
color: scaleConfig.useVisualIndicators
? scale.primaryScale.hoverBorder
: scale.primaryScale.borderText),
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
), ),
boxDecoration: BoxDecoration( boxDecoration: BoxDecoration(
color: scale.primaryScale.hoverBorder, //color: scale.primaryScale.hoverBorder,
borderRadius: BorderRadius.circular(8), border: Border.all(
color: scaleConfig.useVisualIndicators
? scale.primaryScale.hoverBorder
: scale.primaryScale.borderText),
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
), ),
), ),
dropdownOptions: DropdownOptions( dropdownOptions: DropdownOptions(
@ -239,7 +250,8 @@ class _DeveloperPageState extends State<DeveloperPage> {
duration: 150.ms, duration: 150.ms,
color: scale.primaryScale.elementBackground, color: scale.primaryScale.elementBackground,
borderSide: BorderSide(color: scale.primaryScale.border), borderSide: BorderSide(color: scale.primaryScale.border),
borderRadius: BorderRadius.circular(8), borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4), padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
), ),
dropdownTriangleOptions: const DropdownTriangleOptions( dropdownTriangleOptions: const DropdownTriangleOptions(
@ -283,10 +295,12 @@ class _DeveloperPageState extends State<DeveloperPage> {
filled: true, filled: true,
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2), contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(
8 * scaleConfig.borderRadiusScale),
borderSide: BorderSide.none), borderSide: BorderSide.none),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(
8 * scaleConfig.borderRadiusScale),
), ),
fillColor: scale.primaryScale.subtleBackground, fillColor: scale.primaryScale.subtleBackground,
hintText: translate('developer.command'), hintText: translate('developer.command'),

View File

@ -17,6 +17,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.4.1" version: "6.4.1"
animated_bottom_navigation_bar:
dependency: "direct main"
description:
name: animated_bottom_navigation_bar
sha256: "2b04a2ae4b0742669e60ddf309467d6a354cefd2d0cd20f4737b1efaf9834cda"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
animated_switcher_transitions: animated_switcher_transitions:
dependency: "direct main" dependency: "direct main"
description: description:
@ -481,11 +489,9 @@ packages:
flutter_chat_ui: flutter_chat_ui:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "../flutter_chat_ui"
ref: main relative: true
resolved-ref: "0d8ac2fcafe24eba1adff9290a9ccd41f7718480" source: path
url: "https://gitlab.com/veilid/flutter-chat-ui.git"
source: git
version: "1.6.14" version: "1.6.14"
flutter_form_builder: flutter_form_builder:
dependency: "direct main" dependency: "direct main"
@ -1351,14 +1357,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
stylish_bottom_bar:
dependency: "direct main"
description:
name: stylish_bottom_bar
sha256: ca72557a5bd8f44caae9017eb3a73002e9189d7a9d2fac598fa55be13724f32b
url: "https://pub.dev"
source: hosted
version: "1.1.0"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:

View File

@ -8,6 +8,7 @@ environment:
flutter: '>=3.22.1' flutter: '>=3.22.1'
dependencies: dependencies:
animated_bottom_navigation_bar: ^1.3.3
animated_switcher_transitions: ^1.0.0 animated_switcher_transitions: ^1.0.0
animated_theme_switcher: ^2.0.10 animated_theme_switcher: ^2.0.10
ansicolor: ^2.0.2 ansicolor: ^2.0.2
@ -83,7 +84,6 @@ dependencies:
split_view: ^3.2.1 split_view: ^3.2.1
stack_trace: ^1.11.1 stack_trace: ^1.11.1
stream_transform: ^2.1.0 stream_transform: ^2.1.0
stylish_bottom_bar: ^1.1.0
transitioned_indexed_stack: ^1.0.2 transitioned_indexed_stack: ^1.0.2
uuid: ^4.4.0 uuid: ^4.4.0
veilid: veilid:
@ -95,13 +95,13 @@ dependencies:
xterm: ^4.0.0 xterm: ^4.0.0
zxing2: ^0.2.3 zxing2: ^0.2.3
# dependency_overrides: dependency_overrides:
# async_tools: # async_tools:
# path: ../dart_async_tools # path: ../dart_async_tools
# bloc_advanced_tools: # bloc_advanced_tools:
# path: ../bloc_advanced_tools # path: ../bloc_advanced_tools
# flutter_chat_ui: flutter_chat_ui:
# path: ../flutter_chat_ui path: ../flutter_chat_ui
dev_dependencies: dev_dependencies:
build_runner: ^2.4.11 build_runner: ^2.4.11