mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
ui cleanup, new themes
This commit is contained in:
parent
94988718e8
commit
44fe198e5d
@ -4,7 +4,9 @@
|
|||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"settings_tooltip": "Settings",
|
"settings_tooltip": "Settings",
|
||||||
"add_account_tooltip": "Add Account"
|
"add_account_tooltip": "Add Account",
|
||||||
|
"accounts": "Accounts",
|
||||||
|
"version": "Version"
|
||||||
},
|
},
|
||||||
"pager": {
|
"pager": {
|
||||||
"chats": "Chats",
|
"chats": "Chats",
|
||||||
@ -192,6 +194,7 @@
|
|||||||
"eggplant": "Eggplant",
|
"eggplant": "Eggplant",
|
||||||
"lime": "Lime",
|
"lime": "Lime",
|
||||||
"grim": "Grim",
|
"grim": "Grim",
|
||||||
|
"elite": "31337",
|
||||||
"contrast": "Contrast"
|
"contrast": "Contrast"
|
||||||
},
|
},
|
||||||
"brightness": {
|
"brightness": {
|
||||||
|
@ -261,7 +261,7 @@ class _EditAccountPageState extends State<EditAccountPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final displayModalHUD = _isInAsyncCall;
|
final displayModalHUD = _isInAsyncCall;
|
||||||
|
|
||||||
return Scaffold(
|
return StyledScaffold(
|
||||||
// resizeToAvoidBottomInset: false,
|
// resizeToAvoidBottomInset: false,
|
||||||
appBar: DefaultAppBar(
|
appBar: DefaultAppBar(
|
||||||
title: Text(translate('edit_account_page.titlebar')),
|
title: Text(translate('edit_account_page.titlebar')),
|
||||||
|
@ -93,7 +93,7 @@ class _NewAccountPageState extends State<NewAccountPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final displayModalHUD = _isInAsyncCall;
|
final displayModalHUD = _isInAsyncCall;
|
||||||
|
|
||||||
return Scaffold(
|
return StyledScaffold(
|
||||||
// resizeToAvoidBottomInset: false,
|
// resizeToAvoidBottomInset: false,
|
||||||
appBar: DefaultAppBar(
|
appBar: DefaultAppBar(
|
||||||
title: Text(translate('new_account_page.titlebar')),
|
title: Text(translate('new_account_page.titlebar')),
|
||||||
|
@ -21,24 +21,42 @@ class ProfileWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: scale.primaryScale.border,
|
color: scaleConfig.preferBorders
|
||||||
shape:
|
? scale.primaryScale.elementBackground
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))),
|
: scale.primaryScale.border,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: !scaleConfig.useVisualIndicators
|
||||||
|
? BorderSide.none
|
||||||
|
: BorderSide(
|
||||||
|
strokeAlign: BorderSide.strokeAlignCenter,
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText,
|
||||||
|
width: 2),
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale))),
|
||||||
|
),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Text(
|
Text(
|
||||||
_profile.name,
|
_profile.name,
|
||||||
style: textTheme.headlineSmall!
|
style: textTheme.headlineSmall!.copyWith(
|
||||||
.copyWith(color: scale.primaryScale.borderText),
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
).paddingAll(4),
|
).paddingAll(4),
|
||||||
if (_profile.pronouns.isNotEmpty)
|
if (_profile.pronouns.isNotEmpty)
|
||||||
Text(_profile.pronouns,
|
Text(_profile.pronouns,
|
||||||
style: textTheme.bodyMedium!
|
style: textTheme.bodyMedium!.copyWith(
|
||||||
.copyWith(color: scale.primaryScale.borderText))
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText))
|
||||||
.paddingLTRB(4, 0, 4, 4),
|
.paddingLTRB(4, 0, 4, 4),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
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 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
import 'account_manager/account_manager.dart';
|
import 'account_manager/account_manager.dart';
|
||||||
import 'account_manager/cubits/active_local_account_cubit.dart';
|
|
||||||
import 'init.dart';
|
import 'init.dart';
|
||||||
import 'layout/splash.dart';
|
import 'layout/splash.dart';
|
||||||
import 'router/router.dart';
|
import 'router/router.dart';
|
||||||
import 'settings/settings.dart';
|
import 'settings/settings.dart';
|
||||||
import 'theme/models/theme_preference.dart';
|
import 'theme/models/theme_preference.dart';
|
||||||
|
import 'theme/theme.dart';
|
||||||
import 'tick.dart';
|
import 'tick.dart';
|
||||||
import 'tools/loggy.dart';
|
import 'tools/loggy.dart';
|
||||||
import 'veilid_processor/veilid_processor.dart';
|
import 'veilid_processor/veilid_processor.dart';
|
||||||
@ -69,9 +69,7 @@ class VeilidChatApp extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildShortcuts(
|
Widget _buildShortcuts({required Widget Function(BuildContext) builder}) =>
|
||||||
{required BuildContext context,
|
|
||||||
required Widget Function(BuildContext) builder}) =>
|
|
||||||
ThemeSwitcher(
|
ThemeSwitcher(
|
||||||
builder: (context) => Shortcuts(
|
builder: (context) => Shortcuts(
|
||||||
shortcuts: <LogicalKeySet, Intent>{
|
shortcuts: <LogicalKeySet, Intent>{
|
||||||
@ -136,25 +134,42 @@ class VeilidChatApp extends StatelessWidget {
|
|||||||
accountRepository: AccountRepository.instance,
|
accountRepository: AccountRepository.instance,
|
||||||
locator: context.read)),
|
locator: context.read)),
|
||||||
],
|
],
|
||||||
child: BackgroundTicker(
|
child:
|
||||||
child: _buildShortcuts(
|
BackgroundTicker(child: _buildShortcuts(builder: (context) {
|
||||||
context: context,
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
builder: (context) => MaterialApp.router(
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
routerConfig:
|
final gradient = LinearGradient(
|
||||||
context.read<RouterCubit>().router(),
|
begin: Alignment.topLeft,
|
||||||
title: translate('app.title'),
|
end: Alignment.bottomRight,
|
||||||
theme: theme,
|
colors: scaleConfig.preferBorders &&
|
||||||
localizationsDelegates: [
|
theme.brightness == Brightness.light
|
||||||
GlobalMaterialLocalizations.delegate,
|
? [
|
||||||
GlobalWidgetsLocalizations.delegate,
|
scale.grayScale.hoverElementBackground,
|
||||||
FormBuilderLocalizations.delegate,
|
scale.grayScale.subtleBackground,
|
||||||
localizationDelegate
|
]
|
||||||
],
|
: [
|
||||||
supportedLocales:
|
scale.tertiaryScale.hoverElementBackground,
|
||||||
localizationDelegate.supportedLocales,
|
scale.tertiaryScale.subtleBackground,
|
||||||
locale: localizationDelegate.currentLocale,
|
]);
|
||||||
))),
|
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: BoxDecoration(gradient: gradient),
|
||||||
|
child: MaterialApp.router(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
routerConfig: context.read<RouterCubit>().router(),
|
||||||
|
title: translate('app.title'),
|
||||||
|
theme: theme,
|
||||||
|
localizationsDelegates: [
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
FormBuilderLocalizations.delegate,
|
||||||
|
localizationDelegate
|
||||||
|
],
|
||||||
|
supportedLocales: localizationDelegate.supportedLocales,
|
||||||
|
locale: localizationDelegate.currentLocale,
|
||||||
|
));
|
||||||
|
})),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -154,8 +154,9 @@ class ChatComponentWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
final textTheme = Theme.of(context).textTheme;
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
final chatTheme = makeChatTheme(scale, textTheme);
|
final textTheme = theme.textTheme;
|
||||||
|
final chatTheme = makeChatTheme(scale, scaleConfig, textTheme);
|
||||||
final errorChatTheme = (ChatThemeEditor(chatTheme)
|
final errorChatTheme = (ChatThemeEditor(chatTheme)
|
||||||
..inputTextColor = scale.errorScale.primary
|
..inputTextColor = scale.errorScale.primary
|
||||||
..sendButtonIcon = Image.asset(
|
..sendButtonIcon = Image.asset(
|
||||||
@ -191,104 +192,99 @@ class ChatComponentWidget extends StatelessWidget {
|
|||||||
chatComponentCubit.scrollOffset = 0;
|
chatComponentCubit.scrollOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefaultTextStyle(
|
return Align(
|
||||||
style: textTheme.bodySmall!,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: Align(
|
child: Stack(
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
children: [
|
||||||
child: Stack(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Container(
|
||||||
children: [
|
height: 48,
|
||||||
Container(
|
decoration: BoxDecoration(
|
||||||
height: 48,
|
color: scale.primaryScale.subtleBorder,
|
||||||
|
),
|
||||||
|
child: Row(children: [
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(16, 0, 16, 0),
|
||||||
|
child: Text(title,
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
style: textTheme.titleMedium!.copyWith(
|
||||||
|
color: scale.primaryScale.borderText)),
|
||||||
|
)),
|
||||||
|
const Spacer(),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.close,
|
||||||
|
color: scale.primaryScale.borderText),
|
||||||
|
onPressed: () async {
|
||||||
|
context.read<ActiveChatCubit>().setActiveChat(null);
|
||||||
|
}).paddingLTRB(16, 0, 16, 0)
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: scale.primaryScale.subtleBorder,
|
color: scale.primaryScale.subtleBackground),
|
||||||
),
|
child: NotificationListener<ScrollNotification>(
|
||||||
child: Row(children: [
|
onNotification: (notification) {
|
||||||
Align(
|
if (chatComponentCubit.scrollOffset != 0) {
|
||||||
alignment: AlignmentDirectional.centerStart,
|
return false;
|
||||||
child: Padding(
|
}
|
||||||
padding: const EdgeInsetsDirectional.fromSTEB(
|
|
||||||
16, 0, 16, 0),
|
|
||||||
child: Text(title,
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
style: textTheme.titleMedium!.copyWith(
|
|
||||||
color: scale.primaryScale.borderText)),
|
|
||||||
)),
|
|
||||||
const Spacer(),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.close,
|
|
||||||
color: scale.primaryScale.borderText),
|
|
||||||
onPressed: () async {
|
|
||||||
context.read<ActiveChatCubit>().setActiveChat(null);
|
|
||||||
}).paddingLTRB(16, 0, 16, 0)
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: const BoxDecoration(),
|
|
||||||
child: NotificationListener<ScrollNotification>(
|
|
||||||
onNotification: (notification) {
|
|
||||||
if (chatComponentCubit.scrollOffset != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFirstPage &&
|
if (!isFirstPage &&
|
||||||
notification.metrics.pixels <=
|
notification.metrics.pixels <=
|
||||||
((notification.metrics.maxScrollExtent -
|
((notification.metrics.maxScrollExtent -
|
||||||
notification.metrics
|
notification
|
||||||
.minScrollExtent) *
|
.metrics.minScrollExtent) *
|
||||||
(1.0 - onEndReachedThreshold) +
|
(1.0 - onEndReachedThreshold) +
|
||||||
notification
|
notification.metrics.minScrollExtent)) {
|
||||||
.metrics.minScrollExtent)) {
|
//
|
||||||
//
|
final scrollOffset =
|
||||||
final scrollOffset = (notification
|
(notification.metrics.maxScrollExtent -
|
||||||
.metrics.maxScrollExtent -
|
|
||||||
notification.metrics.minScrollExtent) *
|
notification.metrics.minScrollExtent) *
|
||||||
(1.0 - onEndReachedThreshold);
|
(1.0 - onEndReachedThreshold);
|
||||||
|
|
||||||
chatComponentCubit.scrollOffset = scrollOffset;
|
chatComponentCubit.scrollOffset = scrollOffset;
|
||||||
|
|
||||||
//
|
//
|
||||||
singleFuture(chatComponentState.chatKey,
|
singleFuture(chatComponentState.chatKey, () async {
|
||||||
() async {
|
await _handlePageForward(chatComponentCubit,
|
||||||
await _handlePageForward(chatComponentCubit,
|
messageWindow, notification);
|
||||||
messageWindow, notification);
|
});
|
||||||
});
|
} else if (!isLastPage &&
|
||||||
} else if (!isLastPage &&
|
notification.metrics.pixels >=
|
||||||
notification.metrics.pixels >=
|
((notification.metrics.maxScrollExtent -
|
||||||
((notification.metrics.maxScrollExtent -
|
notification
|
||||||
notification.metrics
|
.metrics.minScrollExtent) *
|
||||||
.minScrollExtent) *
|
onEndReachedThreshold +
|
||||||
onEndReachedThreshold +
|
notification.metrics.minScrollExtent)) {
|
||||||
notification
|
//
|
||||||
.metrics.minScrollExtent)) {
|
final scrollOffset =
|
||||||
//
|
-(notification.metrics.maxScrollExtent -
|
||||||
final scrollOffset = -(notification
|
|
||||||
.metrics.maxScrollExtent -
|
|
||||||
notification.metrics.minScrollExtent) *
|
notification.metrics.minScrollExtent) *
|
||||||
(1.0 - onEndReachedThreshold);
|
(1.0 - onEndReachedThreshold);
|
||||||
|
|
||||||
chatComponentCubit.scrollOffset = scrollOffset;
|
chatComponentCubit.scrollOffset = scrollOffset;
|
||||||
//
|
//
|
||||||
singleFuture(chatComponentState.chatKey,
|
singleFuture(chatComponentState.chatKey, () async {
|
||||||
() async {
|
await _handlePageBackward(chatComponentCubit,
|
||||||
await _handlePageBackward(chatComponentCubit,
|
messageWindow, notification);
|
||||||
messageWindow, notification);
|
});
|
||||||
});
|
}
|
||||||
}
|
return false;
|
||||||
return false;
|
},
|
||||||
},
|
child: ValueListenableBuilder(
|
||||||
child: ValueListenableBuilder(
|
valueListenable:
|
||||||
valueListenable:
|
chatComponentState.textEditingController,
|
||||||
chatComponentState.textEditingController,
|
builder: (context, textEditingValue, __) {
|
||||||
builder: (context, textEditingValue, __) {
|
final messageIsValid = utf8
|
||||||
final messageIsValid = utf8
|
.encode(textEditingValue.text)
|
||||||
.encode(textEditingValue.text)
|
.lengthInBytes <
|
||||||
.lengthInBytes <
|
2048;
|
||||||
2048;
|
|
||||||
|
|
||||||
return Chat(
|
return Chat(
|
||||||
key: chatComponentState.chatKey,
|
key: chatComponentState.chatKey,
|
||||||
theme: messageIsValid
|
theme: messageIsValid
|
||||||
? chatTheme
|
? chatTheme
|
||||||
@ -343,13 +339,14 @@ class ChatComponentWidget extends StatelessWidget {
|
|||||||
//showUserAvatars: false,
|
//showUserAvatars: false,
|
||||||
//showUserNames: true,
|
//showUserNames: true,
|
||||||
user: localUser,
|
user: localUser,
|
||||||
emptyState: const EmptyChatWidget());
|
emptyState: const EmptyChatWidget())
|
||||||
}))),
|
.paddingLTRB(0, 2, 0, 0);
|
||||||
),
|
}))),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final signedContactInvitationBytesV =
|
final signedContactInvitationBytesV =
|
||||||
context.watch<InvitationGeneratorCubit>().state;
|
context.watch<InvitationGeneratorCubit>().state;
|
||||||
@ -59,7 +60,8 @@ class ContactInvitationDisplayDialog extends StatelessWidget {
|
|||||||
child: Dialog(
|
child: Dialog(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
side: const BorderSide(width: 2),
|
side: const BorderSide(width: 2),
|
||||||
borderRadius: BorderRadius.circular(16)),
|
borderRadius:
|
||||||
|
BorderRadius.circular(16 * scaleConfig.borderRadiusScale)),
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
|
@ -40,13 +40,14 @@ class ContactInvitationListWidgetState
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
//final textTheme = theme.textTheme;
|
//final textTheme = theme.textTheme;
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
margin: const EdgeInsets.fromLTRB(4, 0, 4, 4),
|
margin: const EdgeInsets.fromLTRB(4, 0, 4, 4),
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
constraints: const BoxConstraints(maxHeight: 200),
|
constraints: const BoxConstraints(maxHeight: 200),
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -54,7 +55,8 @@ class ContactInvitationListWidgetState
|
|||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: scale.primaryScale.subtleBackground,
|
color: scale.primaryScale.subtleBackground,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius:
|
||||||
|
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:async_tools/async_tools.dart';
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
@ -47,18 +48,22 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _wrapInBox({required Widget child, required Color color}) =>
|
Widget _wrapInBox(
|
||||||
|
{required Widget child,
|
||||||
|
required Color color,
|
||||||
|
required double borderRadius}) =>
|
||||||
DecoratedBox(
|
DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: color,
|
color: color,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16))),
|
borderRadius: BorderRadius.circular(borderRadius))),
|
||||||
child: child);
|
child: child);
|
||||||
|
|
||||||
Widget _makeAccountWidget(
|
Widget _makeAccountWidget(
|
||||||
{required String name,
|
{required String name,
|
||||||
required bool selected,
|
required bool selected,
|
||||||
required ScaleColor scale,
|
required ScaleColor scale,
|
||||||
|
required ScaleConfig scaleConfig,
|
||||||
required bool loggedIn,
|
required bool loggedIn,
|
||||||
required void Function()? callback,
|
required void Function()? callback,
|
||||||
required void Function()? footerCallback}) {
|
required void Function()? footerCallback}) {
|
||||||
@ -71,13 +76,37 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
shortname = abbrev;
|
shortname = abbrev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
late final Color background;
|
||||||
|
late final Color hoverBackground;
|
||||||
|
late final Color activeBackground;
|
||||||
|
late final Color border;
|
||||||
|
late final Color hoverBorder;
|
||||||
|
late final Color activeBorder;
|
||||||
|
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
|
||||||
|
background = loggedIn ? scale.border : scale.subtleBorder;
|
||||||
|
hoverBackground = background;
|
||||||
|
activeBackground = background;
|
||||||
|
border =
|
||||||
|
selected ? scale.activeElementBackground : scale.elementBackground;
|
||||||
|
hoverBorder = border;
|
||||||
|
activeBorder = border;
|
||||||
|
} else {
|
||||||
|
background =
|
||||||
|
selected ? scale.activeElementBackground : scale.elementBackground;
|
||||||
|
hoverBackground = scale.hoverElementBackground;
|
||||||
|
activeBackground = scale.activeElementBackground;
|
||||||
|
border = loggedIn ? scale.border : scale.subtleBorder;
|
||||||
|
hoverBorder = scale.hoverBorder;
|
||||||
|
activeBorder = scale.primary;
|
||||||
|
}
|
||||||
|
|
||||||
final avatar = Container(
|
final avatar = Container(
|
||||||
height: 34,
|
height: 34,
|
||||||
width: 34,
|
width: 34,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: loggedIn ? scale.border : scale.subtleBorder,
|
color: border,
|
||||||
width: 2,
|
width: 2,
|
||||||
strokeAlign: BorderSide.strokeAlignOutside),
|
strokeAlign: BorderSide.strokeAlignOutside),
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
@ -89,27 +118,28 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
child: Text(shortname, style: theme.textTheme.titleLarge)));
|
child: Text(shortname, style: theme.textTheme.titleLarge)));
|
||||||
|
|
||||||
return AnimatedPadding(
|
return AnimatedPadding(
|
||||||
padding: EdgeInsets.fromLTRB(selected ? 0 : 0, 0, selected ? 0 : 8, 0),
|
padding: EdgeInsets.fromLTRB(selected ? 0 : 8, selected ? 0 : 2,
|
||||||
|
selected ? 0 : 8, selected ? 0 : 2),
|
||||||
duration: const Duration(milliseconds: 50),
|
duration: const Duration(milliseconds: 50),
|
||||||
child: MenuItemWidget(
|
child: MenuItemWidget(
|
||||||
title: name,
|
title: name,
|
||||||
headerWidget: avatar,
|
headerWidget: avatar,
|
||||||
titleStyle: theme.textTheme.titleLarge!,
|
titleStyle: theme.textTheme.titleSmall!
|
||||||
|
.copyWith(color: scaleConfig.useVisualIndicators ? border : null),
|
||||||
foregroundColor: scale.primary,
|
foregroundColor: scale.primary,
|
||||||
backgroundColor: selected
|
backgroundColor: background,
|
||||||
? scale.activeElementBackground
|
backgroundHoverColor: hoverBackground,
|
||||||
: scale.elementBackground,
|
backgroundFocusColor: activeBackground,
|
||||||
backgroundHoverColor: scale.hoverElementBackground,
|
borderColor: border,
|
||||||
backgroundFocusColor: scale.activeElementBackground,
|
borderHoverColor: hoverBorder,
|
||||||
borderColor: scale.border,
|
borderFocusColor: activeBorder,
|
||||||
borderHoverColor: scale.hoverBorder,
|
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||||
borderFocusColor: scale.primary,
|
|
||||||
callback: callback,
|
callback: callback,
|
||||||
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
||||||
footerCallback: footerCallback,
|
footerCallback: footerCallback,
|
||||||
footerButtonIconColor: scale.border,
|
footerButtonIconColor: border,
|
||||||
footerButtonIconHoverColor: scale.hoverElementBackground,
|
footerButtonIconHoverColor: hoverBackground,
|
||||||
footerButtonIconFocusColor: scale.activeElementBackground,
|
footerButtonIconFocusColor: activeBackground,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +150,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
perAccountCollectionBlocMapState}) {
|
perAccountCollectionBlocMapState}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scaleScheme = theme.extension<ScaleScheme>()!;
|
final scaleScheme = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final loggedInAccounts = <Widget>[];
|
final loggedInAccounts = <Widget>[];
|
||||||
final loggedOutAccounts = <Widget>[];
|
final loggedOutAccounts = <Widget>[];
|
||||||
@ -133,11 +164,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
final avAccountRecordState = perAccountState?.avAccountRecordState;
|
final avAccountRecordState = perAccountState?.avAccountRecordState;
|
||||||
if (perAccountState != null && avAccountRecordState != null) {
|
if (perAccountState != null && avAccountRecordState != null) {
|
||||||
// Account is logged in
|
// Account is logged in
|
||||||
final scale = theme.extension<ScaleScheme>()!.tertiaryScale;
|
final scale = theme.extension<ScaleScheme>()!.primaryScale;
|
||||||
final loggedInAccount = avAccountRecordState.when(
|
final loggedInAccount = avAccountRecordState.when(
|
||||||
data: (value) => _makeAccountWidget(
|
data: (value) => _makeAccountWidget(
|
||||||
name: value.profile.name,
|
name: value.profile.name,
|
||||||
scale: scale,
|
scale: scale,
|
||||||
|
scaleConfig: scaleConfig,
|
||||||
selected: superIdentityRecordKey == activeLocalAccount,
|
selected: superIdentityRecordKey == activeLocalAccount,
|
||||||
loggedIn: true,
|
loggedIn: true,
|
||||||
callback: () {
|
callback: () {
|
||||||
@ -152,10 +184,12 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
}),
|
}),
|
||||||
loading: () => _wrapInBox(
|
loading: () => _wrapInBox(
|
||||||
child: buildProgressIndicator(),
|
child: buildProgressIndicator(),
|
||||||
color: scaleScheme.grayScale.subtleBorder),
|
color: scaleScheme.grayScale.subtleBorder,
|
||||||
|
borderRadius: 16 * scaleConfig.borderRadiusScale),
|
||||||
error: (err, st) => _wrapInBox(
|
error: (err, st) => _wrapInBox(
|
||||||
child: errorPage(err, st),
|
child: errorPage(err, st),
|
||||||
color: scaleScheme.errorScale.subtleBorder),
|
color: scaleScheme.errorScale.subtleBorder,
|
||||||
|
borderRadius: 16 * scaleConfig.borderRadiusScale),
|
||||||
);
|
);
|
||||||
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
|
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
@ -164,6 +198,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
final loggedOutAccount = _makeAccountWidget(
|
final loggedOutAccount = _makeAccountWidget(
|
||||||
name: la.name,
|
name: la.name,
|
||||||
scale: scale,
|
scale: scale,
|
||||||
|
scaleConfig: scaleConfig,
|
||||||
selected: superIdentityRecordKey == activeLocalAccount,
|
selected: superIdentityRecordKey == activeLocalAccount,
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
callback: () => {_doSwitchClick(superIdentityRecordKey)},
|
callback: () => {_doSwitchClick(superIdentityRecordKey)},
|
||||||
@ -185,49 +220,77 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _getButton(
|
Widget _getButton(
|
||||||
{required Icon icon,
|
{required Icon icon,
|
||||||
required ScaleColor scale,
|
required ScaleColor scale,
|
||||||
required String tooltip,
|
required ScaleConfig scaleConfig,
|
||||||
required void Function()? onPressed}) =>
|
required String tooltip,
|
||||||
IconButton(
|
required void Function()? onPressed}) {
|
||||||
icon: icon,
|
late final Color background;
|
||||||
color: scale.hoverBorder,
|
late final Color hoverBackground;
|
||||||
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
late final Color activeBackground;
|
||||||
style: ButtonStyle(
|
late final Color border;
|
||||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
late final Color hoverBorder;
|
||||||
if (states.contains(WidgetState.hovered)) {
|
late final Color activeBorder;
|
||||||
return scale.hoverElementBackground;
|
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
|
||||||
}
|
background = scale.border;
|
||||||
if (states.contains(WidgetState.focused)) {
|
hoverBackground = scale.hoverBorder;
|
||||||
return scale.activeElementBackground;
|
activeBackground = scale.primary;
|
||||||
}
|
border = scale.elementBackground;
|
||||||
return scale.elementBackground;
|
hoverBorder = scale.hoverElementBackground;
|
||||||
}), shape: WidgetStateProperty.resolveWith((states) {
|
activeBorder = scale.activeElementBackground;
|
||||||
if (states.contains(WidgetState.hovered)) {
|
} else {
|
||||||
return RoundedRectangleBorder(
|
background = scale.elementBackground;
|
||||||
side: BorderSide(color: scale.hoverBorder),
|
hoverBackground = scale.hoverElementBackground;
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)));
|
activeBackground = scale.activeElementBackground;
|
||||||
}
|
border = scale.border;
|
||||||
if (states.contains(WidgetState.focused)) {
|
hoverBorder = scale.hoverBorder;
|
||||||
return RoundedRectangleBorder(
|
activeBorder = scale.primary;
|
||||||
side: BorderSide(color: scale.primary),
|
}
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)));
|
return IconButton(
|
||||||
}
|
icon: icon,
|
||||||
|
color: border,
|
||||||
|
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||||
|
if (states.contains(WidgetState.hovered)) {
|
||||||
|
return hoverBackground;
|
||||||
|
}
|
||||||
|
if (states.contains(WidgetState.focused)) {
|
||||||
|
return activeBackground;
|
||||||
|
}
|
||||||
|
return background;
|
||||||
|
}), shape: WidgetStateProperty.resolveWith((states) {
|
||||||
|
if (states.contains(WidgetState.hovered)) {
|
||||||
return RoundedRectangleBorder(
|
return RoundedRectangleBorder(
|
||||||
side: BorderSide(color: scale.border),
|
side: BorderSide(color: hoverBorder),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)));
|
borderRadius: BorderRadius.all(
|
||||||
})),
|
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||||
tooltip: tooltip,
|
}
|
||||||
onPressed: onPressed);
|
if (states.contains(WidgetState.focused)) {
|
||||||
|
return RoundedRectangleBorder(
|
||||||
|
side: BorderSide(color: activeBorder),
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||||
|
}
|
||||||
|
return RoundedRectangleBorder(
|
||||||
|
side: BorderSide(color: border),
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
||||||
|
})),
|
||||||
|
tooltip: tooltip,
|
||||||
|
onPressed: onPressed);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _getBottomButtons() {
|
Widget _getBottomButtons() {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final settingsButton = _getButton(
|
final settingsButton = _getButton(
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
tooltip: translate('menu.settings_tooltip'),
|
tooltip: translate('menu.settings_tooltip'),
|
||||||
scale: scale.tertiaryScale,
|
scale: scale.tertiaryScale,
|
||||||
|
scaleConfig: scaleConfig,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await GoRouterHelper(context).push('/settings');
|
await GoRouterHelper(context).push('/settings');
|
||||||
}).paddingLTRB(0, 0, 16, 0);
|
}).paddingLTRB(0, 0, 16, 0);
|
||||||
@ -236,6 +299,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
tooltip: translate('menu.add_account_tooltip'),
|
tooltip: translate('menu.add_account_tooltip'),
|
||||||
scale: scale.tertiaryScale,
|
scale: scale.tertiaryScale,
|
||||||
|
scaleConfig: scaleConfig,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await GoRouterHelper(context).push('/new_account');
|
await GoRouterHelper(context).push('/new_account');
|
||||||
}).paddingLTRB(0, 0, 16, 0);
|
}).paddingLTRB(0, 0, 16, 0);
|
||||||
@ -259,53 +323,105 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
colors: [
|
colors: [
|
||||||
scale.tertiaryScale.hoverElementBackground,
|
scale.tertiaryScale.subtleBorder,
|
||||||
scale.tertiaryScale.subtleBackground,
|
scale.tertiaryScale.subtleBackground,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
shadows: [
|
shadows: [
|
||||||
BoxShadow(
|
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders)
|
||||||
color: scale.tertiaryScale.appBackground,
|
BoxShadow(
|
||||||
blurRadius: 6,
|
color: scale.tertiaryScale.primary.darken(80),
|
||||||
offset: const Offset(
|
spreadRadius: 2,
|
||||||
0,
|
)
|
||||||
3,
|
else if (scaleConfig.useVisualIndicators &&
|
||||||
|
scaleConfig.preferBorders)
|
||||||
|
BoxShadow(
|
||||||
|
color: scale.tertiaryScale.border,
|
||||||
|
spreadRadius: 2,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
BoxShadow(
|
||||||
|
color: scale.tertiaryScale.primary.darken(40),
|
||||||
|
blurRadius: 6,
|
||||||
|
offset: const Offset(
|
||||||
|
0,
|
||||||
|
4,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
gradient: gradient,
|
gradient: scaleConfig.useVisualIndicators ? null : gradient,
|
||||||
shape: const RoundedRectangleBorder(
|
color: scaleConfig.useVisualIndicators
|
||||||
|
? (scaleConfig.preferBorders
|
||||||
|
? scale.tertiaryScale.appBackground
|
||||||
|
: scale.tertiaryScale.subtleBorder)
|
||||||
|
: null,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: scaleConfig.preferBorders
|
||||||
|
? BorderSide(color: scale.tertiaryScale.primary, width: 2)
|
||||||
|
: BorderSide.none,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topRight: Radius.circular(16),
|
topRight: Radius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
bottomRight: Radius.circular(16)))),
|
bottomRight:
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
FittedBox(
|
FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: Row(children: [
|
child: ColorFiltered(
|
||||||
SvgPicture.asset(
|
colorFilter: ColorFilter.mode(
|
||||||
|
theme.brightness == Brightness.light
|
||||||
|
? scale.tertiaryScale.primary
|
||||||
|
: scale.tertiaryScale.border,
|
||||||
|
scaleConfig.preferBorders
|
||||||
|
? BlendMode.modulate
|
||||||
|
: BlendMode.dst),
|
||||||
|
child: Row(children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
height: 48,
|
||||||
|
'assets/images/icon.svg',
|
||||||
|
colorFilter: scaleConfig.useVisualIndicators
|
||||||
|
? grayColorFilter
|
||||||
|
: null)
|
||||||
|
.paddingLTRB(0, 0, 16, 0),
|
||||||
|
SvgPicture.asset(
|
||||||
height: 48,
|
height: 48,
|
||||||
'assets/images/icon.svg',
|
'assets/images/title.svg',
|
||||||
colorFilter: scaleConfig.useVisualIndicators
|
colorFilter: scaleConfig.useVisualIndicators
|
||||||
? grayColorFilter
|
? grayColorFilter
|
||||||
: null)
|
: null),
|
||||||
.paddingLTRB(0, 0, 16, 0),
|
]))),
|
||||||
SvgPicture.asset(
|
|
||||||
height: 48,
|
|
||||||
'assets/images/title.svg',
|
|
||||||
colorFilter:
|
|
||||||
scaleConfig.useVisualIndicators ? grayColorFilter : null),
|
|
||||||
])),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
_getAccountList(
|
DecoratedBox(
|
||||||
localAccounts: localAccounts,
|
decoration: ShapeDecoration(
|
||||||
activeLocalAccount: activeLocalAccount,
|
shape: RoundedRectangleBorder(
|
||||||
perAccountCollectionBlocMapState: perAccountCollectionBlocMapState),
|
side: !scaleConfig.useVisualIndicators
|
||||||
|
? BorderSide.none
|
||||||
|
: scaleConfig.preferBorders
|
||||||
|
? BorderSide(color: scale.tertiaryScale.border)
|
||||||
|
: BorderSide(color: scale.tertiaryScale.primary),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
16 * scaleConfig.borderRadiusScale)),
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? Colors.transparent
|
||||||
|
: scale.tertiaryScale.border.withAlpha(0x5F)),
|
||||||
|
child: Column(children: [
|
||||||
|
Text(translate('menu.accounts'),
|
||||||
|
style: theme.textTheme.titleMedium!.copyWith(
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.tertiaryScale.border
|
||||||
|
: scale.tertiaryScale.primary))
|
||||||
|
.paddingLTRB(0, 0, 0, 16),
|
||||||
|
_getAccountList(
|
||||||
|
localAccounts: localAccounts,
|
||||||
|
activeLocalAccount: activeLocalAccount,
|
||||||
|
perAccountCollectionBlocMapState:
|
||||||
|
perAccountCollectionBlocMapState)
|
||||||
|
]).paddingAll(16)),
|
||||||
_getBottomButtons(),
|
_getBottomButtons(),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Text('Version $packageInfoVersion',
|
Text('${translate('menu.version')} $packageInfoVersion',
|
||||||
style: theme.textTheme.labelMedium!
|
style: theme.textTheme.labelMedium!
|
||||||
.copyWith(color: scale.tertiaryScale.hoverBorder)),
|
.copyWith(color: scale.tertiaryScale.hoverBorder)),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
@ -315,6 +431,6 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
),
|
),
|
||||||
])
|
])
|
||||||
]).paddingAll(16),
|
]).paddingAll(16),
|
||||||
);
|
).paddingLTRB(0, 2, 2, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
class MenuItemWidget extends StatelessWidget {
|
class MenuItemWidget extends StatelessWidget {
|
||||||
const MenuItemWidget({
|
const MenuItemWidget({
|
||||||
@ -17,6 +16,7 @@ class MenuItemWidget extends StatelessWidget {
|
|||||||
this.borderColor,
|
this.borderColor,
|
||||||
this.borderHoverColor,
|
this.borderHoverColor,
|
||||||
this.borderFocusColor,
|
this.borderFocusColor,
|
||||||
|
this.borderRadius,
|
||||||
this.footerButtonIcon,
|
this.footerButtonIcon,
|
||||||
this.footerButtonIconColor,
|
this.footerButtonIconColor,
|
||||||
this.footerButtonIconHoverColor,
|
this.footerButtonIconHoverColor,
|
||||||
@ -41,18 +41,20 @@ class MenuItemWidget extends StatelessWidget {
|
|||||||
side: WidgetStateBorderSide.resolveWith((states) {
|
side: WidgetStateBorderSide.resolveWith((states) {
|
||||||
if (states.contains(WidgetState.hovered)) {
|
if (states.contains(WidgetState.hovered)) {
|
||||||
return borderColor != null
|
return borderColor != null
|
||||||
? BorderSide(color: borderHoverColor!)
|
? BorderSide(width: 2, color: borderHoverColor!)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
if (states.contains(WidgetState.focused)) {
|
if (states.contains(WidgetState.focused)) {
|
||||||
return borderColor != null
|
return borderColor != null
|
||||||
? BorderSide(color: borderFocusColor!)
|
? BorderSide(width: 2, color: borderFocusColor!)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
return borderColor != null ? BorderSide(color: borderColor!) : null;
|
return borderColor != null
|
||||||
|
? BorderSide(width: 2, color: borderColor!)
|
||||||
|
: null;
|
||||||
}),
|
}),
|
||||||
shape: WidgetStateProperty.all(
|
shape: WidgetStateProperty.all(RoundedRectangleBorder(
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)))),
|
borderRadius: BorderRadius.circular(borderRadius ?? 0)))),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -104,6 +106,7 @@ class MenuItemWidget extends StatelessWidget {
|
|||||||
..add(ColorProperty('backgroundHoverColor', backgroundHoverColor))
|
..add(ColorProperty('backgroundHoverColor', backgroundHoverColor))
|
||||||
..add(ColorProperty('backgroundFocusColor', backgroundFocusColor))
|
..add(ColorProperty('backgroundFocusColor', backgroundFocusColor))
|
||||||
..add(ColorProperty('borderColor', borderColor))
|
..add(ColorProperty('borderColor', borderColor))
|
||||||
|
..add(DoubleProperty('borderRadius', borderRadius))
|
||||||
..add(ColorProperty('borderHoverColor', borderHoverColor))
|
..add(ColorProperty('borderHoverColor', borderHoverColor))
|
||||||
..add(ColorProperty('borderFocusColor', borderFocusColor));
|
..add(ColorProperty('borderFocusColor', borderFocusColor));
|
||||||
}
|
}
|
||||||
@ -122,6 +125,7 @@ class MenuItemWidget extends StatelessWidget {
|
|||||||
final Color? backgroundHoverColor;
|
final Color? backgroundHoverColor;
|
||||||
final Color? backgroundFocusColor;
|
final Color? backgroundFocusColor;
|
||||||
final Color? borderColor;
|
final Color? borderColor;
|
||||||
|
final double? borderRadius;
|
||||||
final Color? borderHoverColor;
|
final Color? borderHoverColor;
|
||||||
final Color? borderFocusColor;
|
final Color? borderFocusColor;
|
||||||
final Color? footerButtonIconColor;
|
final Color? footerButtonIconColor;
|
||||||
|
@ -30,23 +30,39 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||||||
(c) => c.state.asData!.value.profile);
|
(c) => c.state.asData!.value.profile);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
return ColoredBox(
|
return ColoredBox(
|
||||||
color: scale.primaryScale.subtleBorder,
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.subtleBackground
|
||||||
|
: scale.primaryScale.subtleBorder,
|
||||||
child: Column(children: <Widget>[
|
child: Column(children: <Widget>[
|
||||||
Row(children: [
|
Row(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.menu),
|
icon: const Icon(Icons.menu),
|
||||||
color: scale.secondaryScale.borderText,
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText,
|
||||||
constraints:
|
constraints:
|
||||||
const BoxConstraints.expand(height: 64, width: 64),
|
const BoxConstraints.expand(height: 64, width: 64),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor: WidgetStateProperty.all(
|
backgroundColor: WidgetStateProperty.all(
|
||||||
scale.primaryScale.hoverBorder),
|
scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.hoverElementBackground
|
||||||
|
: scale.primaryScale.hoverBorder),
|
||||||
shape: WidgetStateProperty.all(
|
shape: WidgetStateProperty.all(
|
||||||
const RoundedRectangleBorder(
|
RoundedRectangleBorder(
|
||||||
borderRadius:
|
side: !scaleConfig.useVisualIndicators
|
||||||
BorderRadius.all(Radius.circular(16))))),
|
? BorderSide.none
|
||||||
|
: BorderSide(
|
||||||
|
strokeAlign: BorderSide.strokeAlignCenter,
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText,
|
||||||
|
width: 2),
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(
|
||||||
|
16 * scaleConfig.borderRadiusScale))),
|
||||||
|
)),
|
||||||
tooltip: translate('menu.settings_tooltip'),
|
tooltip: translate('menu.settings_tooltip'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final ctrl = context.read<ZoomDrawerController>();
|
final ctrl = context.read<ZoomDrawerController>();
|
||||||
@ -82,6 +98,7 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||||||
final w = MediaQuery.of(context).size.width;
|
final w = MediaQuery.of(context).size.width;
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final children = [
|
final children = [
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
@ -92,7 +109,10 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: 2,
|
width: 2,
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
child: ColoredBox(color: scale.primaryScale.hoverBorder)),
|
child: ColoredBox(
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.subtleBorder
|
||||||
|
: scale.primaryScale.subtleBackground)),
|
||||||
Expanded(child: buildTabletRightPane(context)),
|
Expanded(child: buildTabletRightPane(context)),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ class AccountPageState extends State<AccountPage> {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final cilState = context.watch<ContactInvitationListCubit>().state;
|
final cilState = context.watch<ContactInvitationListCubit>().state;
|
||||||
final cilBusy = cilState.busy;
|
final cilBusy = cilState.busy;
|
||||||
@ -55,10 +56,12 @@ class AccountPageState extends State<AccountPage> {
|
|||||||
backgroundColor: scale.primaryScale.border,
|
backgroundColor: scale.primaryScale.border,
|
||||||
collapsedBackgroundColor: scale.primaryScale.border,
|
collapsedBackgroundColor: scale.primaryScale.border,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius:
|
||||||
|
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
),
|
),
|
||||||
collapsedShape: RoundedRectangleBorder(
|
collapsedShape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius:
|
||||||
|
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
translate('account_page.contact_invitations'),
|
translate('account_page.contact_invitations'),
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:animated_bottom_navigation_bar/'
|
||||||
|
'animated_bottom_navigation_bar.dart';
|
||||||
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
import 'package:preload_page_view/preload_page_view.dart';
|
import 'package:preload_page_view/preload_page_view.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
|
||||||
|
|
||||||
import '../../../../chat/chat.dart';
|
import '../../../../chat/chat.dart';
|
||||||
import '../../../../contact_invitation/contact_invitation.dart';
|
import '../../../../contact_invitation/contact_invitation.dart';
|
||||||
@ -39,7 +41,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool onScrollNotification(ScrollNotification notification) {
|
bool _onScrollNotification(ScrollNotification notification) {
|
||||||
if (notification is UserScrollNotification &&
|
if (notification is UserScrollNotification &&
|
||||||
notification.metrics.axis == Axis.vertical) {
|
notification.metrics.axis == Axis.vertical) {
|
||||||
switch (notification.direction) {
|
switch (notification.direction) {
|
||||||
@ -58,30 +60,6 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BottomBarItem buildBottomBarItem(int index) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
|
||||||
return BottomBarItem(
|
|
||||||
title: Text(_bottomLabelList[index]),
|
|
||||||
icon:
|
|
||||||
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
|
|
||||||
selectedIcon:
|
|
||||||
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
|
|
||||||
backgroundColor: scale.primaryScale.borderText,
|
|
||||||
//badge: const Text('9+'),
|
|
||||||
//showBadge: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BottomBarItem> _buildBottomBarItems() {
|
|
||||||
final bottomBarItems = List<BottomBarItem>.empty(growable: true);
|
|
||||||
for (var index = 0; index < _bottomLabelList.length; index++) {
|
|
||||||
final item = buildBottomBarItem(index);
|
|
||||||
bottomBarItems.add(item);
|
|
||||||
}
|
|
||||||
return bottomBarItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> scanContactInvitationDialog(BuildContext context) async {
|
Future<void> scanContactInvitationDialog(BuildContext context) async {
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
@ -104,6 +82,63 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildBottomBarItem(int index, bool isActive) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
|
final color = scaleConfig.useVisualIndicators
|
||||||
|
? (scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText)
|
||||||
|
: (isActive
|
||||||
|
? (scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText)
|
||||||
|
: (scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.subtleBorder
|
||||||
|
: scale.primaryScale.borderText.withAlpha(0x80)));
|
||||||
|
|
||||||
|
final item = Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
_selectedIconList[index],
|
||||||
|
size: 24,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: Text(
|
||||||
|
_bottomLabelList[index],
|
||||||
|
style: theme.textTheme.labelLarge!.copyWith(
|
||||||
|
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||||
|
color: color),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (scaleConfig.useVisualIndicators && isActive) {
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
14 * scaleConfig.borderRadiusScale),
|
||||||
|
side: BorderSide(
|
||||||
|
width: 2,
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText))),
|
||||||
|
child: item)
|
||||||
|
.paddingLTRB(8, 0, 8, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _bottomSheetBuilder(BuildContext sheetContext, BuildContext context) {
|
Widget _bottomSheetBuilder(BuildContext sheetContext, BuildContext context) {
|
||||||
if (currentPage == 0) {
|
if (currentPage == 0) {
|
||||||
// New contact invitation
|
// New contact invitation
|
||||||
@ -122,12 +157,13 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
//extendBody: true,
|
//extendBody: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
body: NotificationListener<ScrollNotification>(
|
body: NotificationListener<ScrollNotification>(
|
||||||
onNotification: onScrollNotification,
|
onNotification: _onScrollNotification,
|
||||||
child: PreloadPageView(
|
child: PreloadPageView(
|
||||||
key: _pageViewKey,
|
key: _pageViewKey,
|
||||||
controller: pageController,
|
controller: pageController,
|
||||||
@ -148,31 +184,46 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
// style: Theme.of(context).textTheme.headlineSmall,
|
// style: Theme.of(context).textTheme.headlineSmall,
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
bottomNavigationBar: StylishBottomBar(
|
bottomNavigationBar: AnimatedBottomNavigationBar.builder(
|
||||||
backgroundColor: scale.primaryScale.hoverBorder,
|
itemCount: 2,
|
||||||
option: AnimatedBarOptions(
|
height: 64,
|
||||||
inkEffect: true,
|
tabBuilder: _buildBottomBarItem,
|
||||||
inkColor: scale.primaryScale.hoverPrimary,
|
activeIndex: currentPage,
|
||||||
opacity: 0.3,
|
gapLocation: GapLocation.end,
|
||||||
),
|
gapWidth: 90,
|
||||||
items: _buildBottomBarItems(),
|
notchSmoothness: NotchSmoothness.defaultEdge,
|
||||||
hasNotch: true,
|
notchMargin: 4,
|
||||||
fabLocation: StylishBarFabLocation.end,
|
backgroundColor: scaleConfig.preferBorders
|
||||||
currentIndex: currentPage,
|
? scale.primaryScale.hoverElementBackground
|
||||||
|
: scale.primaryScale.hoverBorder,
|
||||||
|
elevation: 0,
|
||||||
onTap: (index) async {
|
onTap: (index) async {
|
||||||
await pageController.animateToPage(index,
|
await pageController.animateToPage(index,
|
||||||
duration: 250.ms, curve: Curves.easeInOut);
|
duration: 250.ms, curve: Curves.easeInOut);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
floatingActionButton: BottomSheetActionButton(
|
floatingActionButton: BottomSheetActionButton(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: CircleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14))),
|
side: !scaleConfig.useVisualIndicators
|
||||||
foregroundColor: scale.secondaryScale.borderText,
|
? BorderSide.none
|
||||||
backgroundColor: scale.secondaryScale.hoverBorder,
|
: BorderSide(
|
||||||
|
strokeAlign: BorderSide.strokeAlignCenter,
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.secondaryScale.border
|
||||||
|
: scale.secondaryScale.borderText,
|
||||||
|
width: 2),
|
||||||
|
),
|
||||||
|
foregroundColor: scaleConfig.preferBorders
|
||||||
|
? scale.secondaryScale.border
|
||||||
|
: scale.secondaryScale.borderText,
|
||||||
|
backgroundColor: scaleConfig.preferBorders
|
||||||
|
? scale.secondaryScale.hoverElementBackground
|
||||||
|
: scale.secondaryScale.hoverBorder,
|
||||||
builder: (context) => Icon(
|
builder: (context) => Icon(
|
||||||
_fabIconList[currentPage],
|
_fabIconList[currentPage],
|
||||||
color: scale.secondaryScale.borderText,
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.secondaryScale.border
|
||||||
|
: scale.secondaryScale.borderText,
|
||||||
),
|
),
|
||||||
bottomSheetBuilder: (sheetContext) =>
|
bottomSheetBuilder: (sheetContext) =>
|
||||||
_bottomSheetBuilder(sheetContext, context)),
|
_bottomSheetBuilder(sheetContext, context)),
|
||||||
|
@ -118,6 +118,23 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _applyPageBorder(Widget child) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
|
return ValueListenableBuilder(
|
||||||
|
valueListenable: _zoomDrawerController.stateNotifier!,
|
||||||
|
child: child,
|
||||||
|
builder: (context, drawerState, staticChild) => clipBorder(
|
||||||
|
clipEnabled: drawerState != DrawerState.closed,
|
||||||
|
borderEnabled:
|
||||||
|
scaleConfig.preferBorders && scaleConfig.useVisualIndicators,
|
||||||
|
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||||
|
borderColor: scale.primaryScale.border,
|
||||||
|
child: staticChild!));
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildAccountPageView(BuildContext context) {
|
Widget _buildAccountPageView(BuildContext context) {
|
||||||
final localAccounts = context.watch<LocalAccountsCubit>().state;
|
final localAccounts = context.watch<LocalAccountsCubit>().state;
|
||||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
||||||
@ -127,7 +144,7 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
final activeIndex = localAccounts
|
final activeIndex = localAccounts
|
||||||
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
|
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
|
||||||
if (activeIndex == -1) {
|
if (activeIndex == -1) {
|
||||||
return const HomeNoActive();
|
return _applyPageBorder(const HomeNoActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
final accountPages = <Widget>[];
|
final accountPages = <Widget>[];
|
||||||
@ -141,7 +158,7 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
}
|
}
|
||||||
final accountPage = _buildAccountPage(
|
final accountPage = _buildAccountPage(
|
||||||
context, superIdentityRecordKey, perAccountCollectionState);
|
context, superIdentityRecordKey, perAccountCollectionState);
|
||||||
accountPages.add(KeyedSubtree.wrap(accountPage, i));
|
accountPages.add(_applyPageBorder(accountPage));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SlideIndexedStack(
|
return SlideIndexedStack(
|
||||||
@ -154,15 +171,6 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
|
||||||
|
|
||||||
final gradient = LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: [
|
|
||||||
scale.tertiaryScale.subtleBackground,
|
|
||||||
scale.tertiaryScale.appBackground,
|
|
||||||
]);
|
|
||||||
|
|
||||||
final localAccounts = context.watch<LocalAccountsCubit>().state;
|
final localAccounts = context.watch<LocalAccountsCubit>().state;
|
||||||
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
final activeLocalAccount = context.watch<ActiveLocalAccountCubit>().state;
|
||||||
@ -171,8 +179,8 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
final canClose = activeIndex != -1;
|
final canClose = activeIndex != -1;
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: DecoratedBox(
|
child: DefaultTextStyle(
|
||||||
decoration: BoxDecoration(gradient: gradient),
|
style: theme.textTheme.bodySmall!,
|
||||||
child: ZoomDrawer(
|
child: ZoomDrawer(
|
||||||
controller: _zoomDrawerController,
|
controller: _zoomDrawerController,
|
||||||
//menuBackgroundColor: Colors.transparent,
|
//menuBackgroundColor: Colors.transparent,
|
||||||
@ -188,18 +196,16 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
mainScreen: Provider<ZoomDrawerController>.value(
|
mainScreen: Provider<ZoomDrawerController>.value(
|
||||||
value: _zoomDrawerController,
|
value: _zoomDrawerController,
|
||||||
child: Builder(builder: _buildAccountPageView)),
|
child: Builder(builder: _buildAccountPageView)),
|
||||||
borderRadius: 24,
|
borderRadius: 0,
|
||||||
//showShadow: false,
|
|
||||||
angle: 0,
|
angle: 0,
|
||||||
drawerShadowsBackgroundColor: theme.shadowColor,
|
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x2F),
|
||||||
mainScreenOverlayColor: theme.shadowColor.withAlpha(0x3F),
|
|
||||||
openCurve: Curves.fastEaseInToSlowEaseOut,
|
openCurve: Curves.fastEaseInToSlowEaseOut,
|
||||||
// duration: const Duration(milliseconds: 250),
|
// duration: const Duration(milliseconds: 250),
|
||||||
// reverseDuration: const Duration(milliseconds: 250),
|
// reverseDuration: const Duration(milliseconds: 250),
|
||||||
menuScreenTapClose: canClose,
|
menuScreenTapClose: canClose,
|
||||||
mainScreenTapClose: canClose,
|
mainScreenTapClose: canClose,
|
||||||
disableDragGesture: !canClose,
|
disableDragGesture: !canClose,
|
||||||
mainScreenScale: .25,
|
mainScreenScale: .15,
|
||||||
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
|
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -36,19 +36,18 @@ class SettingsPageState extends State<SettingsPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) =>
|
Widget build(BuildContext context) =>
|
||||||
AsyncBlocBuilder<PreferencesCubit, Preferences>(
|
AsyncBlocBuilder<PreferencesCubit, Preferences>(
|
||||||
builder: (context, state) => ThemeSwitchingArea(
|
builder: (context, state) => StyledScaffold(
|
||||||
child: Scaffold(
|
appBar: DefaultAppBar(
|
||||||
appBar: DefaultAppBar(
|
title: Text(translate('settings_page.titlebar')),
|
||||||
title: Text(translate('settings_page.titlebar')),
|
leading: IconButton(
|
||||||
leading: IconButton(
|
icon: const Icon(Icons.arrow_back),
|
||||||
icon: const Icon(Icons.arrow_back),
|
onPressed: () => GoRouterHelper(context).pop(),
|
||||||
onPressed: () => GoRouterHelper(context).pop(),
|
),
|
||||||
),
|
actions: <Widget>[
|
||||||
actions: <Widget>[
|
const SignalStrengthMeterWidget().paddingLTRB(16, 0, 16, 0),
|
||||||
const SignalStrengthMeterWidget()
|
]),
|
||||||
.paddingLTRB(16, 0, 16, 0),
|
body: ThemeSwitchingArea(
|
||||||
]),
|
child: FormBuilder(
|
||||||
body: FormBuilder(
|
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
|
@ -5,47 +5,82 @@ import 'package:flutter_chat_ui/flutter_chat_ui.dart';
|
|||||||
|
|
||||||
import 'scale_scheme.dart';
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) =>
|
ChatTheme makeChatTheme(
|
||||||
|
ScaleScheme scale, ScaleConfig scaleConfig, TextTheme textTheme) =>
|
||||||
DefaultChatTheme(
|
DefaultChatTheme(
|
||||||
primaryColor: scale.primaryScale.calloutBackground,
|
primaryColor: scaleConfig.preferBorders
|
||||||
secondaryColor: scale.secondaryScale.calloutBackground,
|
? scale.primaryScale.calloutText
|
||||||
|
: scale.primaryScale.calloutBackground,
|
||||||
|
secondaryColor: scaleConfig.preferBorders
|
||||||
|
? scale.secondaryScale.calloutText
|
||||||
|
: scale.secondaryScale.calloutBackground,
|
||||||
backgroundColor: scale.grayScale.appBackground,
|
backgroundColor: scale.grayScale.appBackground,
|
||||||
|
messageBorderRadius: scaleConfig.borderRadiusScale * 16,
|
||||||
|
bubbleBorderSide: scaleConfig.preferBorders
|
||||||
|
? BorderSide(
|
||||||
|
color: scale.primaryScale.calloutBackground,
|
||||||
|
width: 2,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
sendButtonIcon: Image.asset(
|
sendButtonIcon: Image.asset(
|
||||||
'assets/icon-send.png',
|
'assets/icon-send.png',
|
||||||
color: scale.primaryScale.borderText,
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.border
|
||||||
|
: scale.primaryScale.borderText,
|
||||||
package: 'flutter_chat_ui',
|
package: 'flutter_chat_ui',
|
||||||
),
|
),
|
||||||
inputBackgroundColor: Colors.blue,
|
inputBackgroundColor: Colors.blue,
|
||||||
inputBorderRadius: BorderRadius.zero,
|
inputBorderRadius: BorderRadius.zero,
|
||||||
inputTextDecoration: InputDecoration(
|
inputTextDecoration: InputDecoration(
|
||||||
filled: true,
|
filled: !scaleConfig.preferBorders,
|
||||||
fillColor: scale.primaryScale.elementBackground,
|
fillColor: scale.primaryScale.subtleBackground,
|
||||||
isDense: true,
|
isDense: true,
|
||||||
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
||||||
border: const OutlineInputBorder(
|
disabledBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide.none,
|
borderSide: scaleConfig.preferBorders
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8))),
|
? BorderSide(color: scale.grayScale.border, width: 2)
|
||||||
focusedBorder: const OutlineInputBorder(
|
: BorderSide.none,
|
||||||
borderSide: BorderSide.none,
|
borderRadius: BorderRadius.all(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8))),
|
Radius.circular(8 * scaleConfig.borderRadiusScale))),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: scaleConfig.preferBorders
|
||||||
|
? BorderSide(color: scale.primaryScale.border, width: 2)
|
||||||
|
: BorderSide.none,
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(8 * scaleConfig.borderRadiusScale))),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: scaleConfig.preferBorders
|
||||||
|
? BorderSide(color: scale.primaryScale.border, width: 2)
|
||||||
|
: BorderSide.none,
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(8 * scaleConfig.borderRadiusScale))),
|
||||||
),
|
),
|
||||||
inputContainerDecoration:
|
inputContainerDecoration: BoxDecoration(
|
||||||
BoxDecoration(color: scale.primaryScale.border),
|
border: scaleConfig.preferBorders
|
||||||
inputPadding: const EdgeInsets.all(9),
|
? Border(
|
||||||
inputTextColor: scale.primaryScale.appText,
|
top: BorderSide(color: scale.primaryScale.border, width: 2))
|
||||||
|
: null,
|
||||||
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.elementBackground
|
||||||
|
: scale.primaryScale.border),
|
||||||
|
inputPadding: const EdgeInsets.all(12),
|
||||||
|
inputTextColor: !scaleConfig.preferBorders
|
||||||
|
? scale.primaryScale.appText
|
||||||
|
: scale.primaryScale.border,
|
||||||
attachmentButtonIcon: const Icon(Icons.attach_file),
|
attachmentButtonIcon: const Icon(Icons.attach_file),
|
||||||
sentMessageBodyTextStyle: TextStyle(
|
sentMessageBodyTextStyle: textTheme.bodyLarge!.copyWith(
|
||||||
color: scale.primaryScale.calloutText,
|
color: scaleConfig.preferBorders
|
||||||
fontSize: 16,
|
? scale.primaryScale.calloutBackground
|
||||||
fontWeight: FontWeight.w500,
|
: scale.primaryScale.calloutText,
|
||||||
height: 1.5,
|
|
||||||
),
|
),
|
||||||
sentEmojiMessageTextStyle: const TextStyle(
|
sentEmojiMessageTextStyle: const TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 64,
|
fontSize: 64,
|
||||||
),
|
),
|
||||||
receivedMessageBodyTextStyle: TextStyle(
|
receivedMessageBodyTextStyle: TextStyle(
|
||||||
color: scale.secondaryScale.calloutText,
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.secondaryScale.calloutBackground
|
||||||
|
: scale.secondaryScale.calloutText,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
|
@ -5,11 +5,14 @@ import 'scale_color.dart';
|
|||||||
import 'scale_input_decorator_theme.dart';
|
import 'scale_input_decorator_theme.dart';
|
||||||
import 'scale_scheme.dart';
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
ScaleScheme _contrastScale(Brightness brightness) {
|
ScaleColor _contrastScaleColor(
|
||||||
final back = brightness == Brightness.light ? Colors.white : Colors.black;
|
{required Brightness brightness,
|
||||||
final front = brightness == Brightness.light ? Colors.black : Colors.white;
|
required Color frontColor,
|
||||||
|
required Color backColor}) {
|
||||||
|
final back = brightness == Brightness.light ? backColor : frontColor;
|
||||||
|
final front = brightness == Brightness.light ? frontColor : backColor;
|
||||||
|
|
||||||
final primaryScale = ScaleColor(
|
return ScaleColor(
|
||||||
appBackground: back,
|
appBackground: back,
|
||||||
subtleBackground: back,
|
subtleBackground: back,
|
||||||
elementBackground: back,
|
elementBackground: back,
|
||||||
@ -28,21 +31,236 @@ ScaleScheme _contrastScale(Brightness brightness) {
|
|||||||
calloutBackground: front,
|
calloutBackground: front,
|
||||||
calloutText: back,
|
calloutText: back,
|
||||||
);
|
);
|
||||||
|
|
||||||
return ScaleScheme(
|
|
||||||
primaryScale: primaryScale,
|
|
||||||
primaryAlphaScale: primaryScale,
|
|
||||||
secondaryScale: primaryScale,
|
|
||||||
tertiaryScale: primaryScale,
|
|
||||||
grayScale: primaryScale,
|
|
||||||
errorScale: primaryScale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData contrastGenerator(Brightness brightness) {
|
const kMonoSpaceFontDisplay = 'Source Code Pro';
|
||||||
final textTheme = makeRadixTextTheme(brightness);
|
const kMonoSpaceFontText = 'Source Code Pro';
|
||||||
final scaleScheme = _contrastScale(brightness);
|
|
||||||
final colorScheme = scaleScheme.toColorScheme(brightness);
|
TextTheme makeMonoSpaceTextTheme(Brightness brightness) =>
|
||||||
final scaleConfig = ScaleConfig(useVisualIndicators: true);
|
(brightness == Brightness.light)
|
||||||
|
? const TextTheme(
|
||||||
|
displayLarge: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace displayLarge',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black54,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
displayMedium: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace displayMedium',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black54,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
displaySmall: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace displaySmall',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black54,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
headlineLarge: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace headlineLarge',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black54,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
headlineMedium: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace headlineMedium',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black54,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
headlineSmall: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace headlineSmall',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black87,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
titleLarge: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace titleLarge',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.black87,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
titleMedium: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace titleMedium',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black87,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
titleSmall: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace titleSmall',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
bodyLarge: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace bodyLarge',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black87,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
bodyMedium: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace bodyMedium',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black87,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
bodySmall: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace bodySmall',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black54,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
labelLarge: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace labelLarge',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black87,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
labelMedium: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace labelMedium',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
labelSmall: TextStyle(
|
||||||
|
debugLabel: 'blackMonoSpace labelSmall',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.black,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
)
|
||||||
|
: const TextTheme(
|
||||||
|
displayLarge: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace displayLarge',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white70,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
displayMedium: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace displayMedium',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white70,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
displaySmall: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace displaySmall',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white70,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
headlineLarge: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace headlineLarge',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white70,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
headlineMedium: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace headlineMedium',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white70,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
headlineSmall: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace headlineSmall',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
titleLarge: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace titleLarge',
|
||||||
|
fontFamily: kMonoSpaceFontDisplay,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
titleMedium: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace titleMedium',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
titleSmall: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace titleSmall',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
bodyLarge: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace bodyLarge',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
bodyMedium: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace bodyMedium',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
bodySmall: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace bodySmall',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white70,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
labelLarge: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace labelLarge',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
labelMedium: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace labelMedium',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
labelSmall: TextStyle(
|
||||||
|
debugLabel: 'whiteMonoSpace labelSmall',
|
||||||
|
fontFamily: kMonoSpaceFontText,
|
||||||
|
color: Colors.white,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
);
|
||||||
|
|
||||||
|
ScaleScheme _contrastScaleScheme(
|
||||||
|
{required Brightness brightness,
|
||||||
|
required Color primaryFront,
|
||||||
|
required Color primaryBack,
|
||||||
|
required Color secondaryFront,
|
||||||
|
required Color secondaryBack,
|
||||||
|
required Color tertiaryFront,
|
||||||
|
required Color tertiaryBack,
|
||||||
|
required Color grayFront,
|
||||||
|
required Color grayBack,
|
||||||
|
required Color errorFront,
|
||||||
|
required Color errorBack}) =>
|
||||||
|
ScaleScheme(
|
||||||
|
primaryScale: _contrastScaleColor(
|
||||||
|
brightness: brightness,
|
||||||
|
frontColor: primaryFront,
|
||||||
|
backColor: primaryBack),
|
||||||
|
primaryAlphaScale: _contrastScaleColor(
|
||||||
|
brightness: brightness,
|
||||||
|
frontColor: primaryFront,
|
||||||
|
backColor: primaryBack),
|
||||||
|
secondaryScale: _contrastScaleColor(
|
||||||
|
brightness: brightness,
|
||||||
|
frontColor: secondaryFront,
|
||||||
|
backColor: secondaryBack),
|
||||||
|
tertiaryScale: _contrastScaleColor(
|
||||||
|
brightness: brightness,
|
||||||
|
frontColor: tertiaryFront,
|
||||||
|
backColor: tertiaryBack),
|
||||||
|
grayScale: _contrastScaleColor(
|
||||||
|
brightness: brightness, frontColor: grayFront, backColor: grayBack),
|
||||||
|
errorScale: _contrastScaleColor(
|
||||||
|
brightness: brightness,
|
||||||
|
frontColor: errorFront,
|
||||||
|
backColor: errorBack));
|
||||||
|
|
||||||
|
ThemeData contrastGenerator({
|
||||||
|
required Brightness brightness,
|
||||||
|
required ScaleConfig scaleConfig,
|
||||||
|
required Color primaryFront,
|
||||||
|
required Color primaryBack,
|
||||||
|
required Color secondaryFront,
|
||||||
|
required Color secondaryBack,
|
||||||
|
required Color tertiaryFront,
|
||||||
|
required Color tertiaryBack,
|
||||||
|
required Color grayFront,
|
||||||
|
required Color grayBack,
|
||||||
|
required Color errorFront,
|
||||||
|
required Color errorBack,
|
||||||
|
TextTheme? customTextTheme,
|
||||||
|
}) {
|
||||||
|
final textTheme = customTextTheme ?? makeRadixTextTheme(brightness);
|
||||||
|
final scaleScheme = _contrastScaleScheme(
|
||||||
|
brightness: brightness,
|
||||||
|
primaryFront: primaryFront,
|
||||||
|
primaryBack: primaryBack,
|
||||||
|
secondaryFront: secondaryFront,
|
||||||
|
secondaryBack: secondaryBack,
|
||||||
|
tertiaryFront: tertiaryFront,
|
||||||
|
tertiaryBack: tertiaryBack,
|
||||||
|
grayFront: grayFront,
|
||||||
|
grayBack: grayBack,
|
||||||
|
errorFront: errorFront,
|
||||||
|
errorBack: errorBack,
|
||||||
|
);
|
||||||
|
final colorScheme = scaleScheme.toColorScheme(
|
||||||
|
brightness,
|
||||||
|
);
|
||||||
|
|
||||||
final themeData = ThemeData.from(
|
final themeData = ThemeData.from(
|
||||||
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
||||||
@ -50,10 +268,11 @@ ThemeData contrastGenerator(Brightness brightness) {
|
|||||||
bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
|
bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
modalElevation: 0,
|
modalElevation: 0,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16),
|
topLeft: Radius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
topRight: Radius.circular(16)))),
|
topRight:
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
|
||||||
canvasColor: scaleScheme.primaryScale.subtleBackground,
|
canvasColor: scaleScheme.primaryScale.subtleBackground,
|
||||||
chipTheme: themeData.chipTheme.copyWith(
|
chipTheme: themeData.chipTheme.copyWith(
|
||||||
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
||||||
@ -69,13 +288,15 @@ ThemeData contrastGenerator(Brightness brightness) {
|
|||||||
disabledForegroundColor: scaleScheme.grayScale.appText,
|
disabledForegroundColor: scaleScheme.grayScale.appText,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
side: BorderSide(color: scaleScheme.primaryScale.border),
|
side: BorderSide(color: scaleScheme.primaryScale.border),
|
||||||
borderRadius: BorderRadius.circular(8))),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale))),
|
||||||
),
|
),
|
||||||
textSelectionTheme: TextSelectionThemeData(
|
textSelectionTheme: TextSelectionThemeData(
|
||||||
cursorColor: scaleScheme.primaryScale.appText,
|
cursorColor: scaleScheme.primaryScale.appText,
|
||||||
selectionColor: scaleScheme.primaryScale.appText.withAlpha(0x7F),
|
selectionColor: scaleScheme.primaryScale.appText.withAlpha(0x7F),
|
||||||
selectionHandleColor: scaleScheme.primaryScale.appText),
|
selectionHandleColor: scaleScheme.primaryScale.appText),
|
||||||
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme),
|
inputDecorationTheme:
|
||||||
|
ScaleInputDecoratorTheme(scaleScheme, scaleConfig, textTheme),
|
||||||
extensions: <ThemeExtension<dynamic>>[
|
extensions: <ThemeExtension<dynamic>>[
|
||||||
scaleScheme,
|
scaleScheme,
|
||||||
scaleConfig,
|
scaleConfig,
|
||||||
|
@ -604,7 +604,11 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
|||||||
final radix = _radixScheme(brightness, themeColor);
|
final radix = _radixScheme(brightness, themeColor);
|
||||||
final scaleScheme = radix.toScale();
|
final scaleScheme = radix.toScale();
|
||||||
final colorScheme = scaleScheme.toColorScheme(brightness);
|
final colorScheme = scaleScheme.toColorScheme(brightness);
|
||||||
final scaleConfig = ScaleConfig(useVisualIndicators: false);
|
final scaleConfig = ScaleConfig(
|
||||||
|
useVisualIndicators: false,
|
||||||
|
preferBorders: false,
|
||||||
|
borderRadiusScale: 1,
|
||||||
|
);
|
||||||
|
|
||||||
final themeData = ThemeData.from(
|
final themeData = ThemeData.from(
|
||||||
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
||||||
@ -654,8 +658,10 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
|||||||
disabledForegroundColor: scaleScheme.grayScale.primary,
|
disabledForegroundColor: scaleScheme.grayScale.primary,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
side: BorderSide(color: scaleScheme.primaryScale.border),
|
side: BorderSide(color: scaleScheme.primaryScale.border),
|
||||||
borderRadius: BorderRadius.circular(8))),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale))),
|
||||||
),
|
),
|
||||||
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme),
|
inputDecorationTheme:
|
||||||
|
ScaleInputDecoratorTheme(scaleScheme, scaleConfig, textTheme),
|
||||||
extensions: <ThemeExtension<dynamic>>[scaleScheme, scaleConfig]);
|
extensions: <ThemeExtension<dynamic>>[scaleScheme, scaleConfig]);
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'scale_scheme.dart';
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
class ScaleInputDecoratorTheme extends InputDecorationTheme {
|
class ScaleInputDecoratorTheme extends InputDecorationTheme {
|
||||||
ScaleInputDecoratorTheme(this._scaleScheme, this._textTheme)
|
ScaleInputDecoratorTheme(
|
||||||
|
this._scaleScheme, ScaleConfig scaleConfig, this._textTheme)
|
||||||
: super(
|
: super(
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: _scaleScheme.primaryScale.border),
|
borderSide: BorderSide(color: _scaleScheme.primaryScale.border),
|
||||||
borderRadius: BorderRadius.circular(8)),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale)),
|
||||||
contentPadding: const EdgeInsets.all(8),
|
contentPadding: const EdgeInsets.all(8),
|
||||||
labelStyle: TextStyle(
|
labelStyle: TextStyle(
|
||||||
color: _scaleScheme.primaryScale.subtleText.withAlpha(127)),
|
color: _scaleScheme.primaryScale.subtleText.withAlpha(127)),
|
||||||
@ -16,7 +18,8 @@ class ScaleInputDecoratorTheme extends InputDecorationTheme {
|
|||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: _scaleScheme.primaryScale.hoverBorder, width: 2),
|
color: _scaleScheme.primaryScale.hoverBorder, width: 2),
|
||||||
borderRadius: BorderRadius.circular(8)));
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale)));
|
||||||
|
|
||||||
final ScaleScheme _scaleScheme;
|
final ScaleScheme _scaleScheme;
|
||||||
final TextTheme _textTheme;
|
final TextTheme _textTheme;
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'scale_color.dart';
|
import 'scale_color.dart';
|
||||||
@ -97,7 +100,7 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
|||||||
onSurfaceVariant: secondaryScale.primaryText, // ?? reviewed a little
|
onSurfaceVariant: secondaryScale.primaryText, // ?? reviewed a little
|
||||||
outline: primaryScale.border,
|
outline: primaryScale.border,
|
||||||
outlineVariant: secondaryScale.border,
|
outlineVariant: secondaryScale.border,
|
||||||
shadow: const Color(0xFF000000),
|
shadow: primaryScale.primary.darken(80),
|
||||||
//scrim: primaryScale.background,
|
//scrim: primaryScale.background,
|
||||||
// inverseSurface: primaryScale.subtleText,
|
// inverseSurface: primaryScale.subtleText,
|
||||||
// onInverseSurface: primaryScale.subtleBackground,
|
// onInverseSurface: primaryScale.subtleBackground,
|
||||||
@ -109,16 +112,24 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
|||||||
class ScaleConfig extends ThemeExtension<ScaleConfig> {
|
class ScaleConfig extends ThemeExtension<ScaleConfig> {
|
||||||
ScaleConfig({
|
ScaleConfig({
|
||||||
required this.useVisualIndicators,
|
required this.useVisualIndicators,
|
||||||
|
required this.preferBorders,
|
||||||
|
required this.borderRadiusScale,
|
||||||
});
|
});
|
||||||
|
|
||||||
final bool useVisualIndicators;
|
final bool useVisualIndicators;
|
||||||
|
final bool preferBorders;
|
||||||
|
final double borderRadiusScale;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ScaleConfig copyWith({
|
ScaleConfig copyWith({
|
||||||
bool? useVisualIndicators,
|
bool? useVisualIndicators,
|
||||||
|
bool? preferBorders,
|
||||||
|
double? borderRadiusScale,
|
||||||
}) =>
|
}) =>
|
||||||
ScaleConfig(
|
ScaleConfig(
|
||||||
useVisualIndicators: useVisualIndicators ?? this.useVisualIndicators,
|
useVisualIndicators: useVisualIndicators ?? this.useVisualIndicators,
|
||||||
|
preferBorders: preferBorders ?? this.preferBorders,
|
||||||
|
borderRadiusScale: borderRadiusScale ?? this.borderRadiusScale,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -127,8 +138,10 @@ class ScaleConfig extends ThemeExtension<ScaleConfig> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return ScaleConfig(
|
return ScaleConfig(
|
||||||
useVisualIndicators:
|
useVisualIndicators:
|
||||||
t < .5 ? useVisualIndicators : other.useVisualIndicators,
|
t < .5 ? useVisualIndicators : other.useVisualIndicators,
|
||||||
);
|
preferBorders: t < .5 ? preferBorders : other.preferBorders,
|
||||||
|
borderRadiusScale:
|
||||||
|
lerpDouble(borderRadiusScale, other.borderRadiusScale, t) ?? 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,13 +64,13 @@ class SliderTile extends StatelessWidget {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
final tileColor = scale.scale(!disabled ? tileScale : ScaleKind.gray);
|
final tileColor = scale.scale(!disabled ? tileScale : ScaleKind.gray);
|
||||||
final scalecfg = theme.extension<ScaleConfig>()!;
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
final borderColor = selected ? tileColor.hoverBorder : tileColor.border;
|
final borderColor = selected ? tileColor.hoverBorder : tileColor.border;
|
||||||
final backgroundColor = scalecfg.useVisualIndicators && !selected
|
final backgroundColor = scaleConfig.useVisualIndicators && !selected
|
||||||
? tileColor.borderText
|
? tileColor.borderText
|
||||||
: borderColor;
|
: borderColor;
|
||||||
final textColor = scalecfg.useVisualIndicators && !selected
|
final textColor = scaleConfig.useVisualIndicators && !selected
|
||||||
? borderColor
|
? borderColor
|
||||||
: tileColor.borderText;
|
: tileColor.borderText;
|
||||||
|
|
||||||
@ -79,10 +79,11 @@ class SliderTile extends StatelessWidget {
|
|||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
side: scalecfg.useVisualIndicators
|
side: scaleConfig.useVisualIndicators
|
||||||
? BorderSide(width: 2, color: borderColor, strokeAlign: 0)
|
? BorderSide(width: 2, color: borderColor, strokeAlign: 0)
|
||||||
: BorderSide.none,
|
: BorderSide.none,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
child: Slidable(
|
child: Slidable(
|
||||||
// Specify a key if the Slidable is dismissible.
|
// Specify a key if the Slidable is dismissible.
|
||||||
@ -95,12 +96,12 @@ class SliderTile extends StatelessWidget {
|
|||||||
.map(
|
.map(
|
||||||
(a) => SlidableAction(
|
(a) => SlidableAction(
|
||||||
onPressed: disabled ? null : a.onPressed,
|
onPressed: disabled ? null : a.onPressed,
|
||||||
backgroundColor: scalecfg.useVisualIndicators
|
backgroundColor: scaleConfig.useVisualIndicators
|
||||||
? (selected
|
? (selected
|
||||||
? tileColor.borderText
|
? tileColor.borderText
|
||||||
: tileColor.border)
|
: tileColor.border)
|
||||||
: scale.scale(a.actionScale).primary,
|
: scale.scale(a.actionScale).primary,
|
||||||
foregroundColor: scalecfg.useVisualIndicators
|
foregroundColor: scaleConfig.useVisualIndicators
|
||||||
? (selected
|
? (selected
|
||||||
? tileColor.border
|
? tileColor.border
|
||||||
: tileColor.borderText)
|
: tileColor.borderText)
|
||||||
@ -118,12 +119,12 @@ class SliderTile extends StatelessWidget {
|
|||||||
.map(
|
.map(
|
||||||
(a) => SlidableAction(
|
(a) => SlidableAction(
|
||||||
onPressed: disabled ? null : a.onPressed,
|
onPressed: disabled ? null : a.onPressed,
|
||||||
backgroundColor: scalecfg.useVisualIndicators
|
backgroundColor: scaleConfig.useVisualIndicators
|
||||||
? (selected
|
? (selected
|
||||||
? tileColor.borderText
|
? tileColor.borderText
|
||||||
: tileColor.border)
|
: tileColor.border)
|
||||||
: scale.scale(a.actionScale).primary,
|
: scale.scale(a.actionScale).primary,
|
||||||
foregroundColor: scalecfg.useVisualIndicators
|
foregroundColor: scaleConfig.useVisualIndicators
|
||||||
? (selected
|
? (selected
|
||||||
? tileColor.border
|
? tileColor.border
|
||||||
: tileColor.borderText)
|
: tileColor.borderText)
|
||||||
@ -134,7 +135,7 @@ class SliderTile extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
.toList()),
|
.toList()),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: scalecfg.useVisualIndicators
|
padding: scaleConfig.useVisualIndicators
|
||||||
? EdgeInsets.zero
|
? EdgeInsets.zero
|
||||||
: const EdgeInsets.fromLTRB(0, 2, 0, 2),
|
: const EdgeInsets.fromLTRB(0, 2, 0, 2),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
@ -5,6 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||||||
import '../views/widget_helpers.dart';
|
import '../views/widget_helpers.dart';
|
||||||
import 'contrast_generator.dart';
|
import 'contrast_generator.dart';
|
||||||
import 'radix_generator.dart';
|
import 'radix_generator.dart';
|
||||||
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
part 'theme_preference.freezed.dart';
|
part 'theme_preference.freezed.dart';
|
||||||
part 'theme_preference.g.dart';
|
part 'theme_preference.g.dart';
|
||||||
@ -37,6 +38,7 @@ enum ColorPreference {
|
|||||||
lime,
|
lime,
|
||||||
grim,
|
grim,
|
||||||
// Accessible Colors
|
// Accessible Colors
|
||||||
|
elite,
|
||||||
contrast;
|
contrast;
|
||||||
|
|
||||||
factory ColorPreference.fromJson(dynamic j) =>
|
factory ColorPreference.fromJson(dynamic j) =>
|
||||||
@ -63,7 +65,7 @@ class ThemePreferences with _$ThemePreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension ThemePreferencesExt on ThemePreferences {
|
extension ThemePreferencesExt on ThemePreferences {
|
||||||
/// Get material 'ThemeData' for existinb
|
/// Get material 'ThemeData' for existing theme
|
||||||
ThemeData themeData() {
|
ThemeData themeData() {
|
||||||
late final Brightness brightness;
|
late final Brightness brightness;
|
||||||
switch (brightnessPreference) {
|
switch (brightnessPreference) {
|
||||||
@ -83,8 +85,60 @@ extension ThemePreferencesExt on ThemePreferences {
|
|||||||
switch (colorPreference) {
|
switch (colorPreference) {
|
||||||
// Special cases
|
// Special cases
|
||||||
case ColorPreference.contrast:
|
case ColorPreference.contrast:
|
||||||
// xxx do contrastGenerator
|
themeData = contrastGenerator(
|
||||||
themeData = contrastGenerator(brightness);
|
brightness: brightness,
|
||||||
|
scaleConfig: ScaleConfig(
|
||||||
|
useVisualIndicators: true,
|
||||||
|
preferBorders: false,
|
||||||
|
borderRadiusScale: 1),
|
||||||
|
primaryFront: Colors.black,
|
||||||
|
primaryBack: Colors.white,
|
||||||
|
secondaryFront: Colors.black,
|
||||||
|
secondaryBack: Colors.white,
|
||||||
|
tertiaryFront: Colors.black,
|
||||||
|
tertiaryBack: Colors.white,
|
||||||
|
grayFront: Colors.black,
|
||||||
|
grayBack: Colors.white,
|
||||||
|
errorFront: Colors.black,
|
||||||
|
errorBack: Colors.white,
|
||||||
|
);
|
||||||
|
case ColorPreference.elite:
|
||||||
|
themeData = brightness == Brightness.light
|
||||||
|
? contrastGenerator(
|
||||||
|
brightness: Brightness.light,
|
||||||
|
scaleConfig: ScaleConfig(
|
||||||
|
useVisualIndicators: true,
|
||||||
|
preferBorders: true,
|
||||||
|
borderRadiusScale: 0.2),
|
||||||
|
primaryFront: const Color(0xFF000000),
|
||||||
|
primaryBack: const Color(0xFF00FF00),
|
||||||
|
secondaryFront: const Color(0xFF000000),
|
||||||
|
secondaryBack: const Color(0xFF00FFFF),
|
||||||
|
tertiaryFront: const Color(0xFF000000),
|
||||||
|
tertiaryBack: const Color(0xFFFF00FF),
|
||||||
|
grayFront: const Color(0xFF000000),
|
||||||
|
grayBack: const Color(0xFFFFFFFF),
|
||||||
|
errorFront: const Color(0xFFC0C0C0),
|
||||||
|
errorBack: const Color(0xFF0000FF),
|
||||||
|
customTextTheme: makeMonoSpaceTextTheme(Brightness.light))
|
||||||
|
: contrastGenerator(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
scaleConfig: ScaleConfig(
|
||||||
|
useVisualIndicators: true,
|
||||||
|
preferBorders: true,
|
||||||
|
borderRadiusScale: 0.5),
|
||||||
|
primaryFront: const Color(0xFF000000),
|
||||||
|
primaryBack: const Color(0xFF00FF00),
|
||||||
|
secondaryFront: const Color(0xFF000000),
|
||||||
|
secondaryBack: const Color(0xFF00FFFF),
|
||||||
|
tertiaryFront: const Color(0xFF000000),
|
||||||
|
tertiaryBack: const Color(0xFFFF00FF),
|
||||||
|
grayFront: const Color(0xFF000000),
|
||||||
|
grayBack: const Color(0xFFFFFFFF),
|
||||||
|
errorFront: const Color(0xFF0000FF),
|
||||||
|
errorBack: const Color(0xFFC0C0C0),
|
||||||
|
customTextTheme: makeMonoSpaceTextTheme(Brightness.dark),
|
||||||
|
);
|
||||||
// Generate from Radix
|
// Generate from Radix
|
||||||
case ColorPreference.scarlet:
|
case ColorPreference.scarlet:
|
||||||
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);
|
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);
|
||||||
|
@ -22,6 +22,7 @@ List<DropdownMenuItem<dynamic>> _getThemeDropdownItems() {
|
|||||||
ColorPreference.eggplant: translate('themes.eggplant'),
|
ColorPreference.eggplant: translate('themes.eggplant'),
|
||||||
ColorPreference.lime: translate('themes.lime'),
|
ColorPreference.lime: translate('themes.lime'),
|
||||||
ColorPreference.grim: translate('themes.grim'),
|
ColorPreference.grim: translate('themes.grim'),
|
||||||
|
ColorPreference.elite: translate('themes.elite'),
|
||||||
ColorPreference.contrast: translate('themes.contrast')
|
ColorPreference.contrast: translate('themes.contrast')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,12 +11,14 @@ class StyledDialog extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale)),
|
||||||
),
|
),
|
||||||
contentPadding: const EdgeInsets.all(4),
|
contentPadding: const EdgeInsets.all(4),
|
||||||
backgroundColor: scale.primaryScale.dialogBorder,
|
backgroundColor: scale.primaryScale.dialogBorder,
|
||||||
@ -31,12 +33,14 @@ class StyledDialog extends StatelessWidget {
|
|||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: scale.primaryScale.border,
|
color: scale.primaryScale.border,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16))),
|
borderRadius: BorderRadius.circular(
|
||||||
|
16 * scaleConfig.borderRadiusScale))),
|
||||||
child: DecoratedBox(
|
child: DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: scale.primaryScale.appBackground,
|
color: scale.primaryScale.appBackground,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12))),
|
borderRadius: BorderRadius.circular(
|
||||||
|
12 * scaleConfig.borderRadiusScale))),
|
||||||
child: child.paddingAll(0))));
|
child: child.paddingAll(0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 'color_preferences.dart';
|
||||||
export 'scanner_error_widget.dart';
|
export 'scanner_error_widget.dart';
|
||||||
export 'styled_dialog.dart';
|
export 'styled_dialog.dart';
|
||||||
|
export 'styled_scaffold.dart';
|
||||||
export 'widget_helpers.dart';
|
export 'widget_helpers.dart';
|
||||||
|
@ -132,7 +132,7 @@ void showErrorToast(BuildContext context, String message) {
|
|||||||
contentPadding: const EdgeInsets.all(16),
|
contentPadding: const EdgeInsets.all(16),
|
||||||
primaryColor: scale.errorScale.elementBackground,
|
primaryColor: scale.errorScale.elementBackground,
|
||||||
secondaryColor: scale.errorScale.calloutBackground,
|
secondaryColor: scale.errorScale.calloutBackground,
|
||||||
borderRadius: 16,
|
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||||
toastDuration: const Duration(seconds: 4),
|
toastDuration: const Duration(seconds: 4),
|
||||||
animationDuration: const Duration(milliseconds: 1000),
|
animationDuration: const Duration(milliseconds: 1000),
|
||||||
displayBorder: scaleConfig.useVisualIndicators,
|
displayBorder: scaleConfig.useVisualIndicators,
|
||||||
@ -152,7 +152,7 @@ void showInfoToast(BuildContext context, String message) {
|
|||||||
contentPadding: const EdgeInsets.all(16),
|
contentPadding: const EdgeInsets.all(16),
|
||||||
primaryColor: scale.tertiaryScale.elementBackground,
|
primaryColor: scale.tertiaryScale.elementBackground,
|
||||||
secondaryColor: scale.tertiaryScale.calloutBackground,
|
secondaryColor: scale.tertiaryScale.calloutBackground,
|
||||||
borderRadius: 16,
|
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
||||||
toastDuration: const Duration(seconds: 2),
|
toastDuration: const Duration(seconds: 2),
|
||||||
animationDuration: const Duration(milliseconds: 500),
|
animationDuration: const Duration(milliseconds: 500),
|
||||||
displayBorder: scaleConfig.useVisualIndicators,
|
displayBorder: scaleConfig.useVisualIndicators,
|
||||||
@ -170,13 +170,15 @@ Widget styledTitleContainer({
|
|||||||
}) {
|
}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: borderColor ?? scale.primaryScale.border,
|
color: borderColor ?? scale.primaryScale.border,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius:
|
||||||
|
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Text(
|
Text(
|
||||||
@ -189,7 +191,8 @@ Widget styledTitleContainer({
|
|||||||
color:
|
color:
|
||||||
backgroundColor ?? scale.primaryScale.subtleBackground,
|
backgroundColor ?? scale.primaryScale.subtleBackground,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(
|
||||||
|
16 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
child: child)
|
child: child)
|
||||||
.paddingAll(4)
|
.paddingAll(4)
|
||||||
@ -207,15 +210,17 @@ Widget styledBottomSheet({
|
|||||||
}) {
|
}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: borderColor ?? scale.primaryScale.dialogBorder,
|
color: borderColor ?? scale.primaryScale.dialogBorder,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16),
|
topLeft: Radius.circular(16 * scaleConfig.borderRadiusScale),
|
||||||
topRight: Radius.circular(16)))),
|
topRight:
|
||||||
|
Radius.circular(16 * scaleConfig.borderRadiusScale)))),
|
||||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
@ -226,10 +231,12 @@ Widget styledBottomSheet({
|
|||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color:
|
color:
|
||||||
backgroundColor ?? scale.primaryScale.subtleBackground,
|
backgroundColor ?? scale.primaryScale.subtleBackground,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16),
|
topLeft: Radius.circular(
|
||||||
topRight: Radius.circular(16)))),
|
16 * scaleConfig.borderRadiusScale),
|
||||||
|
topRight: Radius.circular(
|
||||||
|
16 * scaleConfig.borderRadiusScale)))),
|
||||||
child: child)
|
child: child)
|
||||||
.paddingLTRB(4, 4, 4, 0)
|
.paddingLTRB(4, 4, 4, 0)
|
||||||
]));
|
]));
|
||||||
@ -261,3 +268,25 @@ const grayColorFilter = ColorFilter.matrix(<double>[
|
|||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Widget clipBorder({
|
||||||
|
required bool clipEnabled,
|
||||||
|
required bool borderEnabled,
|
||||||
|
required double borderRadius,
|
||||||
|
required Color borderColor,
|
||||||
|
required Widget child,
|
||||||
|
}) =>
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: clipEnabled
|
||||||
|
? BorderRadius.circular(borderRadius)
|
||||||
|
: BorderRadius.zero,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(boxShadow: [
|
||||||
|
if (borderEnabled) BoxShadow(color: borderColor, spreadRadius: 2)
|
||||||
|
]),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: clipEnabled
|
||||||
|
? BorderRadius.circular(borderRadius)
|
||||||
|
: BorderRadius.zero,
|
||||||
|
child: child,
|
||||||
|
)).paddingAll(clipEnabled && borderEnabled ? 2 : 0));
|
||||||
|
@ -51,6 +51,7 @@ class _EnterPinDialogState extends State<EnterPinDialog> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
final focusedBorderColor = scale.primaryScale.hoverBorder;
|
final focusedBorderColor = scale.primaryScale.hoverBorder;
|
||||||
final fillColor = scale.primaryScale.elementBackground;
|
final fillColor = scale.primaryScale.elementBackground;
|
||||||
final borderColor = scale.primaryScale.border;
|
final borderColor = scale.primaryScale.border;
|
||||||
@ -61,7 +62,7 @@ class _EnterPinDialogState extends State<EnterPinDialog> {
|
|||||||
textStyle: TextStyle(fontSize: 22, color: scale.primaryScale.appText),
|
textStyle: TextStyle(fontSize: 22, color: scale.primaryScale.appText),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: fillColor,
|
color: fillColor,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||||
border: Border.all(color: borderColor),
|
border: Border.all(color: borderColor),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -140,6 +140,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final textTheme = theme.textTheme;
|
final textTheme = theme.textTheme;
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
// if (!_isScrolling && _wantsBottom) {
|
// if (!_isScrolling && _wantsBottom) {
|
||||||
@ -225,12 +226,22 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
.copyWith(color: scale.primaryScale.primaryText),
|
.copyWith(color: scale.primaryScale.primaryText),
|
||||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||||
openBoxDecoration: BoxDecoration(
|
openBoxDecoration: BoxDecoration(
|
||||||
color: scale.primaryScale.border,
|
//color: scale.primaryScale.border,
|
||||||
borderRadius: BorderRadius.circular(8),
|
border: Border.all(
|
||||||
|
color: scaleConfig.useVisualIndicators
|
||||||
|
? scale.primaryScale.hoverBorder
|
||||||
|
: scale.primaryScale.borderText),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||||
),
|
),
|
||||||
boxDecoration: BoxDecoration(
|
boxDecoration: BoxDecoration(
|
||||||
color: scale.primaryScale.hoverBorder,
|
//color: scale.primaryScale.hoverBorder,
|
||||||
borderRadius: BorderRadius.circular(8),
|
border: Border.all(
|
||||||
|
color: scaleConfig.useVisualIndicators
|
||||||
|
? scale.primaryScale.hoverBorder
|
||||||
|
: scale.primaryScale.borderText),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownOptions: DropdownOptions(
|
dropdownOptions: DropdownOptions(
|
||||||
@ -239,7 +250,8 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
duration: 150.ms,
|
duration: 150.ms,
|
||||||
color: scale.primaryScale.elementBackground,
|
color: scale.primaryScale.elementBackground,
|
||||||
borderSide: BorderSide(color: scale.primaryScale.border),
|
borderSide: BorderSide(color: scale.primaryScale.border),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8 * scaleConfig.borderRadiusScale),
|
||||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||||
),
|
),
|
||||||
dropdownTriangleOptions: const DropdownTriangleOptions(
|
dropdownTriangleOptions: const DropdownTriangleOptions(
|
||||||
@ -283,10 +295,12 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
filled: true,
|
filled: true,
|
||||||
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale),
|
||||||
borderSide: BorderSide.none),
|
borderSide: BorderSide.none),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale),
|
||||||
),
|
),
|
||||||
fillColor: scale.primaryScale.subtleBackground,
|
fillColor: scale.primaryScale.subtleBackground,
|
||||||
hintText: translate('developer.command'),
|
hintText: translate('developer.command'),
|
||||||
|
24
pubspec.lock
24
pubspec.lock
@ -17,6 +17,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.4.1"
|
version: "6.4.1"
|
||||||
|
animated_bottom_navigation_bar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: animated_bottom_navigation_bar
|
||||||
|
sha256: "2b04a2ae4b0742669e60ddf309467d6a354cefd2d0cd20f4737b1efaf9834cda"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.3"
|
||||||
animated_switcher_transitions:
|
animated_switcher_transitions:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -481,11 +489,9 @@ packages:
|
|||||||
flutter_chat_ui:
|
flutter_chat_ui:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "../flutter_chat_ui"
|
||||||
ref: main
|
relative: true
|
||||||
resolved-ref: "0d8ac2fcafe24eba1adff9290a9ccd41f7718480"
|
source: path
|
||||||
url: "https://gitlab.com/veilid/flutter-chat-ui.git"
|
|
||||||
source: git
|
|
||||||
version: "1.6.14"
|
version: "1.6.14"
|
||||||
flutter_form_builder:
|
flutter_form_builder:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
@ -1351,14 +1357,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
stylish_bottom_bar:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: stylish_bottom_bar
|
|
||||||
sha256: ca72557a5bd8f44caae9017eb3a73002e9189d7a9d2fac598fa55be13724f32b
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -8,6 +8,7 @@ environment:
|
|||||||
flutter: '>=3.22.1'
|
flutter: '>=3.22.1'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
animated_bottom_navigation_bar: ^1.3.3
|
||||||
animated_switcher_transitions: ^1.0.0
|
animated_switcher_transitions: ^1.0.0
|
||||||
animated_theme_switcher: ^2.0.10
|
animated_theme_switcher: ^2.0.10
|
||||||
ansicolor: ^2.0.2
|
ansicolor: ^2.0.2
|
||||||
@ -83,7 +84,6 @@ dependencies:
|
|||||||
split_view: ^3.2.1
|
split_view: ^3.2.1
|
||||||
stack_trace: ^1.11.1
|
stack_trace: ^1.11.1
|
||||||
stream_transform: ^2.1.0
|
stream_transform: ^2.1.0
|
||||||
stylish_bottom_bar: ^1.1.0
|
|
||||||
transitioned_indexed_stack: ^1.0.2
|
transitioned_indexed_stack: ^1.0.2
|
||||||
uuid: ^4.4.0
|
uuid: ^4.4.0
|
||||||
veilid:
|
veilid:
|
||||||
@ -95,13 +95,13 @@ dependencies:
|
|||||||
xterm: ^4.0.0
|
xterm: ^4.0.0
|
||||||
zxing2: ^0.2.3
|
zxing2: ^0.2.3
|
||||||
|
|
||||||
# dependency_overrides:
|
dependency_overrides:
|
||||||
# async_tools:
|
# async_tools:
|
||||||
# path: ../dart_async_tools
|
# path: ../dart_async_tools
|
||||||
# bloc_advanced_tools:
|
# bloc_advanced_tools:
|
||||||
# path: ../bloc_advanced_tools
|
# path: ../bloc_advanced_tools
|
||||||
# flutter_chat_ui:
|
flutter_chat_ui:
|
||||||
# path: ../flutter_chat_ui
|
path: ../flutter_chat_ui
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.11
|
build_runner: ^2.4.11
|
||||||
|
Loading…
Reference in New Issue
Block a user