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": {
"settings_tooltip": "Settings",
"add_account_tooltip": "Add Account"
"add_account_tooltip": "Add Account",
"accounts": "Accounts",
"version": "Version"
},
"pager": {
"chats": "Chats",
@ -192,6 +194,7 @@
"eggplant": "Eggplant",
"lime": "Lime",
"grim": "Grim",
"elite": "31337",
"contrast": "Contrast"
},
"brightness": {

View File

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

View File

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

View File

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

View File

@ -11,12 +11,12 @@ import 'package:provider/provider.dart';
import 'package:veilid_support/veilid_support.dart';
import 'account_manager/account_manager.dart';
import 'account_manager/cubits/active_local_account_cubit.dart';
import 'init.dart';
import 'layout/splash.dart';
import 'router/router.dart';
import 'settings/settings.dart';
import 'theme/models/theme_preference.dart';
import 'theme/theme.dart';
import 'tick.dart';
import 'tools/loggy.dart';
import 'veilid_processor/veilid_processor.dart';
@ -69,9 +69,7 @@ class VeilidChatApp extends StatelessWidget {
});
}
Widget _buildShortcuts(
{required BuildContext context,
required Widget Function(BuildContext) builder}) =>
Widget _buildShortcuts({required Widget Function(BuildContext) builder}) =>
ThemeSwitcher(
builder: (context) => Shortcuts(
shortcuts: <LogicalKeySet, Intent>{
@ -136,25 +134,42 @@ class VeilidChatApp extends StatelessWidget {
accountRepository: AccountRepository.instance,
locator: context.read)),
],
child: BackgroundTicker(
child: _buildShortcuts(
context: context,
builder: (context) => 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,
))),
child:
BackgroundTicker(child: _buildShortcuts(builder: (context) {
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final gradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: scaleConfig.preferBorders &&
theme.brightness == Brightness.light
? [
scale.grayScale.hoverElementBackground,
scale.grayScale.subtleBackground,
]
: [
scale.tertiaryScale.hoverElementBackground,
scale.tertiaryScale.subtleBackground,
]);
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) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final textTheme = Theme.of(context).textTheme;
final chatTheme = makeChatTheme(scale, textTheme);
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme;
final chatTheme = makeChatTheme(scale, scaleConfig, textTheme);
final errorChatTheme = (ChatThemeEditor(chatTheme)
..inputTextColor = scale.errorScale.primary
..sendButtonIcon = Image.asset(
@ -191,104 +192,99 @@ class ChatComponentWidget extends StatelessWidget {
chatComponentCubit.scrollOffset = 0;
}
return DefaultTextStyle(
style: textTheme.bodySmall!,
child: Align(
alignment: AlignmentDirectional.centerEnd,
child: Stack(
return Align(
alignment: AlignmentDirectional.centerEnd,
child: Stack(
children: [
Column(
children: [
Column(
children: [
Container(
height: 48,
Container(
height: 48,
decoration: BoxDecoration(
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(
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: const BoxDecoration(),
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (chatComponentCubit.scrollOffset != 0) {
return false;
}
color: scale.primaryScale.subtleBackground),
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (chatComponentCubit.scrollOffset != 0) {
return false;
}
if (!isFirstPage &&
notification.metrics.pixels <=
((notification.metrics.maxScrollExtent -
notification.metrics
.minScrollExtent) *
(1.0 - onEndReachedThreshold) +
notification
.metrics.minScrollExtent)) {
//
final scrollOffset = (notification
.metrics.maxScrollExtent -
if (!isFirstPage &&
notification.metrics.pixels <=
((notification.metrics.maxScrollExtent -
notification
.metrics.minScrollExtent) *
(1.0 - onEndReachedThreshold) +
notification.metrics.minScrollExtent)) {
//
final scrollOffset =
(notification.metrics.maxScrollExtent -
notification.metrics.minScrollExtent) *
(1.0 - onEndReachedThreshold);
chatComponentCubit.scrollOffset = scrollOffset;
chatComponentCubit.scrollOffset = scrollOffset;
//
singleFuture(chatComponentState.chatKey,
() async {
await _handlePageForward(chatComponentCubit,
messageWindow, notification);
});
} else if (!isLastPage &&
notification.metrics.pixels >=
((notification.metrics.maxScrollExtent -
notification.metrics
.minScrollExtent) *
onEndReachedThreshold +
notification
.metrics.minScrollExtent)) {
//
final scrollOffset = -(notification
.metrics.maxScrollExtent -
//
singleFuture(chatComponentState.chatKey, () async {
await _handlePageForward(chatComponentCubit,
messageWindow, notification);
});
} else if (!isLastPage &&
notification.metrics.pixels >=
((notification.metrics.maxScrollExtent -
notification
.metrics.minScrollExtent) *
onEndReachedThreshold +
notification.metrics.minScrollExtent)) {
//
final scrollOffset =
-(notification.metrics.maxScrollExtent -
notification.metrics.minScrollExtent) *
(1.0 - onEndReachedThreshold);
chatComponentCubit.scrollOffset = scrollOffset;
//
singleFuture(chatComponentState.chatKey,
() async {
await _handlePageBackward(chatComponentCubit,
messageWindow, notification);
});
}
return false;
},
child: ValueListenableBuilder(
valueListenable:
chatComponentState.textEditingController,
builder: (context, textEditingValue, __) {
final messageIsValid = utf8
.encode(textEditingValue.text)
.lengthInBytes <
2048;
chatComponentCubit.scrollOffset = scrollOffset;
//
singleFuture(chatComponentState.chatKey, () async {
await _handlePageBackward(chatComponentCubit,
messageWindow, notification);
});
}
return false;
},
child: ValueListenableBuilder(
valueListenable:
chatComponentState.textEditingController,
builder: (context, textEditingValue, __) {
final messageIsValid = utf8
.encode(textEditingValue.text)
.lengthInBytes <
2048;
return Chat(
return Chat(
key: chatComponentState.chatKey,
theme: messageIsValid
? chatTheme
@ -343,13 +339,14 @@ class ChatComponentWidget extends StatelessWidget {
//showUserAvatars: false,
//showUserNames: true,
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) {
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final scaleConfig = theme.extension<ScaleConfig>()!;
final signedContactInvitationBytesV =
context.watch<InvitationGeneratorCubit>().state;
@ -59,7 +60,8 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
child: Dialog(
shape: RoundedRectangleBorder(
side: const BorderSide(width: 2),
borderRadius: BorderRadius.circular(16)),
borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale)),
backgroundColor: Colors.white,
child: ConstrainedBox(
constraints: BoxConstraints(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,14 @@
import 'dart:async';
import 'package:animated_bottom_navigation_bar/'
'animated_bottom_navigation_bar.dart';
import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:preload_page_view/preload_page_view.dart';
import 'package:provider/provider.dart';
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
import '../../../../chat/chat.dart';
import '../../../../contact_invitation/contact_invitation.dart';
@ -39,7 +41,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
super.dispose();
}
bool onScrollNotification(ScrollNotification notification) {
bool _onScrollNotification(ScrollNotification notification) {
if (notification is UserScrollNotification &&
notification.metrics.axis == Axis.vertical) {
switch (notification.direction) {
@ -58,30 +60,6 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
return false;
}
BottomBarItem buildBottomBarItem(int index) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
return BottomBarItem(
title: Text(_bottomLabelList[index]),
icon:
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
selectedIcon:
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
backgroundColor: scale.primaryScale.borderText,
//badge: const Text('9+'),
//showBadge: true,
);
}
List<BottomBarItem> _buildBottomBarItems() {
final bottomBarItems = List<BottomBarItem>.empty(growable: true);
for (var index = 0; index < _bottomLabelList.length; index++) {
final item = buildBottomBarItem(index);
bottomBarItems.add(item);
}
return bottomBarItems;
}
Future<void> scanContactInvitationDialog(BuildContext context) async {
await showDialog<void>(
context: context,
@ -104,6 +82,63 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
});
}
Widget _buildBottomBarItem(int index, bool isActive) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final color = scaleConfig.useVisualIndicators
? (scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText)
: (isActive
? (scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText)
: (scaleConfig.preferBorders
? scale.primaryScale.subtleBorder
: scale.primaryScale.borderText.withAlpha(0x80)));
final item = Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
_selectedIconList[index],
size: 24,
color: color,
),
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text(
_bottomLabelList[index],
style: theme.textTheme.labelLarge!.copyWith(
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
color: color),
),
)
],
);
if (scaleConfig.useVisualIndicators && isActive) {
return DecoratedBox(
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
14 * scaleConfig.borderRadiusScale),
side: BorderSide(
width: 2,
color: scaleConfig.preferBorders
? scale.primaryScale.border
: scale.primaryScale.borderText))),
child: item)
.paddingLTRB(8, 0, 8, 6);
}
return item;
}
Widget _bottomSheetBuilder(BuildContext sheetContext, BuildContext context) {
if (currentPage == 0) {
// New contact invitation
@ -122,12 +157,13 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
return Scaffold(
//extendBody: true,
backgroundColor: Colors.transparent,
body: NotificationListener<ScrollNotification>(
onNotification: onScrollNotification,
onNotification: _onScrollNotification,
child: PreloadPageView(
key: _pageViewKey,
controller: pageController,
@ -148,31 +184,46 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
// style: Theme.of(context).textTheme.headlineSmall,
// ),
// ),
bottomNavigationBar: StylishBottomBar(
backgroundColor: scale.primaryScale.hoverBorder,
option: AnimatedBarOptions(
inkEffect: true,
inkColor: scale.primaryScale.hoverPrimary,
opacity: 0.3,
),
items: _buildBottomBarItems(),
hasNotch: true,
fabLocation: StylishBarFabLocation.end,
currentIndex: currentPage,
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
itemCount: 2,
height: 64,
tabBuilder: _buildBottomBarItem,
activeIndex: currentPage,
gapLocation: GapLocation.end,
gapWidth: 90,
notchSmoothness: NotchSmoothness.defaultEdge,
notchMargin: 4,
backgroundColor: scaleConfig.preferBorders
? scale.primaryScale.hoverElementBackground
: scale.primaryScale.hoverBorder,
elevation: 0,
onTap: (index) async {
await pageController.animateToPage(index,
duration: 250.ms, curve: Curves.easeInOut);
},
),
floatingActionButton: BottomSheetActionButton(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14))),
foregroundColor: scale.secondaryScale.borderText,
backgroundColor: scale.secondaryScale.hoverBorder,
shape: CircleBorder(
side: !scaleConfig.useVisualIndicators
? BorderSide.none
: BorderSide(
strokeAlign: BorderSide.strokeAlignCenter,
color: scaleConfig.preferBorders
? scale.secondaryScale.border
: scale.secondaryScale.borderText,
width: 2),
),
foregroundColor: scaleConfig.preferBorders
? scale.secondaryScale.border
: scale.secondaryScale.borderText,
backgroundColor: scaleConfig.preferBorders
? scale.secondaryScale.hoverElementBackground
: scale.secondaryScale.hoverBorder,
builder: (context) => Icon(
_fabIconList[currentPage],
color: scale.secondaryScale.borderText,
color: scaleConfig.preferBorders
? scale.secondaryScale.border
: scale.secondaryScale.borderText,
),
bottomSheetBuilder: (sheetContext) =>
_bottomSheetBuilder(sheetContext, context)),

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

View File

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

View File

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

View File

@ -5,11 +5,14 @@ import 'scale_color.dart';
import 'scale_input_decorator_theme.dart';
import 'scale_scheme.dart';
ScaleScheme _contrastScale(Brightness brightness) {
final back = brightness == Brightness.light ? Colors.white : Colors.black;
final front = brightness == Brightness.light ? Colors.black : Colors.white;
ScaleColor _contrastScaleColor(
{required Brightness brightness,
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,
subtleBackground: back,
elementBackground: back,
@ -28,21 +31,236 @@ ScaleScheme _contrastScale(Brightness brightness) {
calloutBackground: front,
calloutText: back,
);
return ScaleScheme(
primaryScale: primaryScale,
primaryAlphaScale: primaryScale,
secondaryScale: primaryScale,
tertiaryScale: primaryScale,
grayScale: primaryScale,
errorScale: primaryScale);
}
ThemeData contrastGenerator(Brightness brightness) {
final textTheme = makeRadixTextTheme(brightness);
final scaleScheme = _contrastScale(brightness);
final colorScheme = scaleScheme.toColorScheme(brightness);
final scaleConfig = ScaleConfig(useVisualIndicators: true);
const kMonoSpaceFontDisplay = 'Source Code Pro';
const kMonoSpaceFontText = 'Source Code Pro';
TextTheme makeMonoSpaceTextTheme(Brightness brightness) =>
(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(
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
@ -50,10 +268,11 @@ ThemeData contrastGenerator(Brightness brightness) {
bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
elevation: 0,
modalElevation: 0,
shape: const RoundedRectangleBorder(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16)))),
topLeft: Radius.circular(16 * scaleConfig.borderRadiusScale),
topRight:
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
canvasColor: scaleScheme.primaryScale.subtleBackground,
chipTheme: themeData.chipTheme.copyWith(
backgroundColor: scaleScheme.primaryScale.elementBackground,
@ -69,13 +288,15 @@ ThemeData contrastGenerator(Brightness brightness) {
disabledForegroundColor: scaleScheme.grayScale.appText,
shape: RoundedRectangleBorder(
side: BorderSide(color: scaleScheme.primaryScale.border),
borderRadius: BorderRadius.circular(8))),
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale))),
),
textSelectionTheme: TextSelectionThemeData(
cursorColor: scaleScheme.primaryScale.appText,
selectionColor: scaleScheme.primaryScale.appText.withAlpha(0x7F),
selectionHandleColor: scaleScheme.primaryScale.appText),
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme),
inputDecorationTheme:
ScaleInputDecoratorTheme(scaleScheme, scaleConfig, textTheme),
extensions: <ThemeExtension<dynamic>>[
scaleScheme,
scaleConfig,

View File

@ -604,7 +604,11 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
final radix = _radixScheme(brightness, themeColor);
final scaleScheme = radix.toScale();
final colorScheme = scaleScheme.toColorScheme(brightness);
final scaleConfig = ScaleConfig(useVisualIndicators: false);
final scaleConfig = ScaleConfig(
useVisualIndicators: false,
preferBorders: false,
borderRadiusScale: 1,
);
final themeData = ThemeData.from(
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
@ -654,8 +658,10 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
disabledForegroundColor: scaleScheme.grayScale.primary,
shape: RoundedRectangleBorder(
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]);
}

View File

@ -3,11 +3,13 @@ import 'package:flutter/material.dart';
import 'scale_scheme.dart';
class ScaleInputDecoratorTheme extends InputDecorationTheme {
ScaleInputDecoratorTheme(this._scaleScheme, this._textTheme)
ScaleInputDecoratorTheme(
this._scaleScheme, ScaleConfig scaleConfig, this._textTheme)
: super(
border: OutlineInputBorder(
borderSide: BorderSide(color: _scaleScheme.primaryScale.border),
borderRadius: BorderRadius.circular(8)),
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale)),
contentPadding: const EdgeInsets.all(8),
labelStyle: TextStyle(
color: _scaleScheme.primaryScale.subtleText.withAlpha(127)),
@ -16,7 +18,8 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: _scaleScheme.primaryScale.hoverBorder, width: 2),
borderRadius: BorderRadius.circular(8)));
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale)));
final ScaleScheme _scaleScheme;
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 'scale_color.dart';
@ -97,7 +100,7 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
onSurfaceVariant: secondaryScale.primaryText, // ?? reviewed a little
outline: primaryScale.border,
outlineVariant: secondaryScale.border,
shadow: const Color(0xFF000000),
shadow: primaryScale.primary.darken(80),
//scrim: primaryScale.background,
// inverseSurface: primaryScale.subtleText,
// onInverseSurface: primaryScale.subtleBackground,
@ -109,16 +112,24 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
class ScaleConfig extends ThemeExtension<ScaleConfig> {
ScaleConfig({
required this.useVisualIndicators,
required this.preferBorders,
required this.borderRadiusScale,
});
final bool useVisualIndicators;
final bool preferBorders;
final double borderRadiusScale;
@override
ScaleConfig copyWith({
bool? useVisualIndicators,
bool? preferBorders,
double? borderRadiusScale,
}) =>
ScaleConfig(
useVisualIndicators: useVisualIndicators ?? this.useVisualIndicators,
preferBorders: preferBorders ?? this.preferBorders,
borderRadiusScale: borderRadiusScale ?? this.borderRadiusScale,
);
@override
@ -127,8 +138,10 @@ class ScaleConfig extends ThemeExtension<ScaleConfig> {
return this;
}
return ScaleConfig(
useVisualIndicators:
t < .5 ? useVisualIndicators : other.useVisualIndicators,
);
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 scale = theme.extension<ScaleScheme>()!;
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 backgroundColor = scalecfg.useVisualIndicators && !selected
final backgroundColor = scaleConfig.useVisualIndicators && !selected
? tileColor.borderText
: borderColor;
final textColor = scalecfg.useVisualIndicators && !selected
final textColor = scaleConfig.useVisualIndicators && !selected
? borderColor
: tileColor.borderText;
@ -79,10 +79,11 @@ class SliderTile extends StatelessWidget {
decoration: ShapeDecoration(
color: backgroundColor,
shape: RoundedRectangleBorder(
side: scalecfg.useVisualIndicators
side: scaleConfig.useVisualIndicators
? BorderSide(width: 2, color: borderColor, strokeAlign: 0)
: BorderSide.none,
borderRadius: BorderRadius.circular(8),
borderRadius:
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
)),
child: Slidable(
// Specify a key if the Slidable is dismissible.
@ -95,12 +96,12 @@ class SliderTile extends StatelessWidget {
.map(
(a) => SlidableAction(
onPressed: disabled ? null : a.onPressed,
backgroundColor: scalecfg.useVisualIndicators
backgroundColor: scaleConfig.useVisualIndicators
? (selected
? tileColor.borderText
: tileColor.border)
: scale.scale(a.actionScale).primary,
foregroundColor: scalecfg.useVisualIndicators
foregroundColor: scaleConfig.useVisualIndicators
? (selected
? tileColor.border
: tileColor.borderText)
@ -118,12 +119,12 @@ class SliderTile extends StatelessWidget {
.map(
(a) => SlidableAction(
onPressed: disabled ? null : a.onPressed,
backgroundColor: scalecfg.useVisualIndicators
backgroundColor: scaleConfig.useVisualIndicators
? (selected
? tileColor.borderText
: tileColor.border)
: scale.scale(a.actionScale).primary,
foregroundColor: scalecfg.useVisualIndicators
foregroundColor: scaleConfig.useVisualIndicators
? (selected
? tileColor.border
: tileColor.borderText)
@ -134,7 +135,7 @@ class SliderTile extends StatelessWidget {
)
.toList()),
child: Padding(
padding: scalecfg.useVisualIndicators
padding: scaleConfig.useVisualIndicators
? EdgeInsets.zero
: const EdgeInsets.fromLTRB(0, 2, 0, 2),
child: ListTile(

View File

@ -5,6 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../views/widget_helpers.dart';
import 'contrast_generator.dart';
import 'radix_generator.dart';
import 'scale_scheme.dart';
part 'theme_preference.freezed.dart';
part 'theme_preference.g.dart';
@ -37,6 +38,7 @@ enum ColorPreference {
lime,
grim,
// Accessible Colors
elite,
contrast;
factory ColorPreference.fromJson(dynamic j) =>
@ -63,7 +65,7 @@ class ThemePreferences with _$ThemePreferences {
}
extension ThemePreferencesExt on ThemePreferences {
/// Get material 'ThemeData' for existinb
/// Get material 'ThemeData' for existing theme
ThemeData themeData() {
late final Brightness brightness;
switch (brightnessPreference) {
@ -83,8 +85,60 @@ extension ThemePreferencesExt on ThemePreferences {
switch (colorPreference) {
// Special cases
case ColorPreference.contrast:
// xxx do contrastGenerator
themeData = contrastGenerator(brightness);
themeData = contrastGenerator(
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
case ColorPreference.scarlet:
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);

View File

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

View File

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

View File

@ -132,7 +132,7 @@ void showErrorToast(BuildContext context, String message) {
contentPadding: const EdgeInsets.all(16),
primaryColor: scale.errorScale.elementBackground,
secondaryColor: scale.errorScale.calloutBackground,
borderRadius: 16,
borderRadius: 16 * scaleConfig.borderRadiusScale,
toastDuration: const Duration(seconds: 4),
animationDuration: const Duration(milliseconds: 1000),
displayBorder: scaleConfig.useVisualIndicators,
@ -152,7 +152,7 @@ void showInfoToast(BuildContext context, String message) {
contentPadding: const EdgeInsets.all(16),
primaryColor: scale.tertiaryScale.elementBackground,
secondaryColor: scale.tertiaryScale.calloutBackground,
borderRadius: 16,
borderRadius: 16 * scaleConfig.borderRadiusScale,
toastDuration: const Duration(seconds: 2),
animationDuration: const Duration(milliseconds: 500),
displayBorder: scaleConfig.useVisualIndicators,
@ -170,13 +170,15 @@ Widget styledTitleContainer({
}) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme;
return DecoratedBox(
decoration: ShapeDecoration(
color: borderColor ?? scale.primaryScale.border,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
borderRadius:
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
)),
child: Column(children: [
Text(
@ -189,7 +191,8 @@ Widget styledTitleContainer({
color:
backgroundColor ?? scale.primaryScale.subtleBackground,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
borderRadius: BorderRadius.circular(
16 * scaleConfig.borderRadiusScale),
)),
child: child)
.paddingAll(4)
@ -207,15 +210,17 @@ Widget styledBottomSheet({
}) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme;
return DecoratedBox(
decoration: ShapeDecoration(
color: borderColor ?? scale.primaryScale.dialogBorder,
shape: const RoundedRectangleBorder(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16)))),
topLeft: Radius.circular(16 * scaleConfig.borderRadiusScale),
topRight:
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Text(
title,
@ -226,10 +231,12 @@ Widget styledBottomSheet({
decoration: ShapeDecoration(
color:
backgroundColor ?? scale.primaryScale.subtleBackground,
shape: const RoundedRectangleBorder(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16)))),
topLeft: Radius.circular(
16 * scaleConfig.borderRadiusScale),
topRight: Radius.circular(
16 * scaleConfig.borderRadiusScale)))),
child: child)
.paddingLTRB(4, 4, 4, 0)
]));
@ -261,3 +268,25 @@ const grayColorFilter = ColorFilter.matrix(<double>[
1,
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) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final focusedBorderColor = scale.primaryScale.hoverBorder;
final fillColor = scale.primaryScale.elementBackground;
final borderColor = scale.primaryScale.border;
@ -61,7 +62,7 @@ class _EnterPinDialogState extends State<EnterPinDialog> {
textStyle: TextStyle(fontSize: 22, color: scale.primaryScale.appText),
decoration: BoxDecoration(
color: fillColor,
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
border: Border.all(color: borderColor),
),
);

View File

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

View File

@ -17,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: "direct main"
description:
@ -481,11 +489,9 @@ packages:
flutter_chat_ui:
dependency: "direct main"
description:
path: "."
ref: main
resolved-ref: "0d8ac2fcafe24eba1adff9290a9ccd41f7718480"
url: "https://gitlab.com/veilid/flutter-chat-ui.git"
source: git
path: "../flutter_chat_ui"
relative: true
source: path
version: "1.6.14"
flutter_form_builder:
dependency: "direct main"
@ -1351,14 +1357,6 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:

View File

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