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