mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
unify handling of themes
accessible theming/high contrast support
This commit is contained in:
parent
23ec185324
commit
4f02435964
@ -6,7 +6,6 @@
|
|||||||
"settings_tooltip": "Settings"
|
"settings_tooltip": "Settings"
|
||||||
},
|
},
|
||||||
"pager": {
|
"pager": {
|
||||||
"account": "Account",
|
|
||||||
"chats": "Chats",
|
"chats": "Chats",
|
||||||
"contacts": "Contacts"
|
"contacts": "Contacts"
|
||||||
},
|
},
|
||||||
@ -67,6 +66,9 @@
|
|||||||
"add_chat_sheet": {
|
"add_chat_sheet": {
|
||||||
"new_chat": "New Chat"
|
"new_chat": "New Chat"
|
||||||
},
|
},
|
||||||
|
"chat": {
|
||||||
|
"say_something": "Say Something"
|
||||||
|
},
|
||||||
"create_invitation_dialog": {
|
"create_invitation_dialog": {
|
||||||
"title": "Create Contact Invitation",
|
"title": "Create Contact Invitation",
|
||||||
"connect_with_me": "Connect with me on VeilidChat!",
|
"connect_with_me": "Connect with me on VeilidChat!",
|
||||||
|
@ -7,6 +7,7 @@ import 'package:form_builder_validators/form_builder_validators.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
import '../../../layout/default_app_bar.dart';
|
import '../../../layout/default_app_bar.dart';
|
||||||
|
import '../../../theme/theme.dart';
|
||||||
import '../../../tools/tools.dart';
|
import '../../../tools/tools.dart';
|
||||||
import '../../../veilid_processor/veilid_processor.dart';
|
import '../../../veilid_processor/veilid_processor.dart';
|
||||||
import '../../account_manager.dart';
|
import '../../account_manager.dart';
|
||||||
|
@ -31,11 +31,14 @@ class ProfileWidget extends StatelessWidget {
|
|||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Text(
|
Text(
|
||||||
_profile.name,
|
_profile.name,
|
||||||
style: textTheme.headlineSmall,
|
style: textTheme.headlineSmall!
|
||||||
|
.copyWith(color: scale.primaryScale.borderText),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
).paddingAll(4),
|
).paddingAll(4),
|
||||||
if (_profile.pronouns.isNotEmpty)
|
if (_profile.pronouns.isNotEmpty)
|
||||||
Text(_profile.pronouns, style: textTheme.bodyMedium)
|
Text(_profile.pronouns,
|
||||||
|
style: textTheme.bodyMedium!
|
||||||
|
.copyWith(color: scale.primaryScale.borderText))
|
||||||
.paddingLTRB(4, 0, 4, 4),
|
.paddingLTRB(4, 0, 4, 4),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,6 @@ import '../../chat_list/chat_list.dart';
|
|||||||
import '../../contacts/contacts.dart';
|
import '../../contacts/contacts.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
|
||||||
import '../chat.dart';
|
import '../chat.dart';
|
||||||
|
|
||||||
class ChatComponent extends StatelessWidget {
|
class ChatComponent extends StatelessWidget {
|
||||||
@ -173,11 +172,13 @@ class ChatComponent extends StatelessWidget {
|
|||||||
16, 0, 16, 0),
|
16, 0, 16, 0),
|
||||||
child: Text(_remoteUser.firstName!,
|
child: Text(_remoteUser.firstName!,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: textTheme.titleMedium),
|
style: textTheme.titleMedium!.copyWith(
|
||||||
|
color: scale.primaryScale.borderText)),
|
||||||
)),
|
)),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.close),
|
icon: Icon(Icons.close,
|
||||||
|
color: scale.primaryScale.borderText),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
context.read<ActiveChatCubit>().setActiveChat(null);
|
context.read<ActiveChatCubit>().setActiveChat(null);
|
||||||
}).paddingLTRB(16, 0, 16, 0)
|
}).paddingLTRB(16, 0, 16, 0)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
|
||||||
|
import '../../theme/theme.dart';
|
||||||
|
|
||||||
class EmptyChatWidget extends StatelessWidget {
|
class EmptyChatWidget extends StatelessWidget {
|
||||||
const EmptyChatWidget({super.key});
|
const EmptyChatWidget({super.key});
|
||||||
@ -7,28 +10,32 @@ class EmptyChatWidget extends StatelessWidget {
|
|||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(
|
Widget build(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) =>
|
) {
|
||||||
Container(
|
final theme = Theme.of(context);
|
||||||
width: double.infinity,
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
height: double.infinity,
|
|
||||||
decoration: BoxDecoration(
|
return Container(
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
width: double.infinity,
|
||||||
),
|
height: double.infinity,
|
||||||
child: Column(
|
decoration: BoxDecoration(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
children: [
|
),
|
||||||
Icon(
|
child: Column(
|
||||||
Icons.chat,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
color: Theme.of(context).disabledColor,
|
children: [
|
||||||
size: 48,
|
Icon(
|
||||||
),
|
Icons.chat,
|
||||||
Text(
|
color: scale.primaryScale.subtleBorder,
|
||||||
'Say Something',
|
size: 48,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
),
|
||||||
color: Theme.of(context).disabledColor,
|
Text(
|
||||||
),
|
translate('chat.say_something'),
|
||||||
),
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
],
|
color: scale.primaryScale.subtleBorder,
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,11 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
|
||||||
|
|
||||||
Widget newChatBottomSheetBuilder(
|
Widget newChatBottomSheetBuilder(
|
||||||
BuildContext sheetContext, BuildContext context) {
|
BuildContext sheetContext, BuildContext context) {
|
||||||
final theme = Theme.of(sheetContext);
|
//final theme = Theme.of(sheetContext);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
//final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
|
||||||
return KeyboardListener(
|
return KeyboardListener(
|
||||||
focusNode: FocusNode(),
|
focusNode: FocusNode(),
|
||||||
@ -23,49 +22,10 @@ Widget newChatBottomSheetBuilder(
|
|||||||
title: translate('add_chat_sheet.new_chat'),
|
title: translate('add_chat_sheet.new_chat'),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 160,
|
height: 160,
|
||||||
child: Row(
|
child: const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Group and custom chat functionality is not available yet')
|
'Group and custom chat functionality is not available yet')
|
||||||
// Column(children: [
|
|
||||||
// IconButton(
|
|
||||||
// onPressed: () async {
|
|
||||||
// Navigator.pop(sheetContext);
|
|
||||||
// await CreateInvitationDialog.show(context);
|
|
||||||
// },
|
|
||||||
// iconSize: 64,
|
|
||||||
// icon: const Icon(Icons.contact_page),
|
|
||||||
// color: scale.primaryScale.background),
|
|
||||||
// Text(
|
|
||||||
// translate('accounts_menu.create_invite'),
|
|
||||||
// )
|
|
||||||
// ]),
|
|
||||||
// Column(children: [
|
|
||||||
// IconButton(
|
|
||||||
// onPressed: () async {
|
|
||||||
// Navigator.pop(sheetContext);
|
|
||||||
// await ScanInvitationDialog.show(context);
|
|
||||||
// },
|
|
||||||
// iconSize: 64,
|
|
||||||
// icon: const Icon(Icons.qr_code_scanner),
|
|
||||||
// color: scale.primaryScale.background),
|
|
||||||
// Text(
|
|
||||||
// translate('accounts_menu.scan_invite'),
|
|
||||||
// )
|
|
||||||
// ]),
|
|
||||||
// Column(children: [
|
|
||||||
// IconButton(
|
|
||||||
// onPressed: () async {
|
|
||||||
// Navigator.pop(sheetContext);
|
|
||||||
// await PasteInvitationDialog.show(context);
|
|
||||||
// },
|
|
||||||
// iconSize: 64,
|
|
||||||
// icon: const Icon(Icons.paste),
|
|
||||||
// color: scale.primaryScale.background),
|
|
||||||
// Text(
|
|
||||||
// translate('accounts_menu.paste_invite'),
|
|
||||||
// )
|
|
||||||
// ])
|
|
||||||
]).paddingAll(16))));
|
]).paddingAll(16))));
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import 'package:async_tools/async_tools.dart';
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:flutter/foundation.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_slidable/flutter_slidable.dart';
|
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
import '../../chat/cubits/active_chat_cubit.dart';
|
import '../../chat/cubits/active_chat_cubit.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
@ -25,85 +23,35 @@ class ChatSingleContactItemWidget extends StatelessWidget {
|
|||||||
Widget build(
|
Widget build(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
//final textTheme = theme.textTheme;
|
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
|
||||||
|
|
||||||
final activeChatCubit = context.watch<ActiveChatCubit>();
|
final activeChatCubit = context.watch<ActiveChatCubit>();
|
||||||
final remoteConversationRecordKey =
|
final remoteConversationRecordKey =
|
||||||
_contact.remoteConversationRecordKey.toVeilid();
|
_contact.remoteConversationRecordKey.toVeilid();
|
||||||
final selected = activeChatCubit.state == remoteConversationRecordKey;
|
final selected = activeChatCubit.state == remoteConversationRecordKey;
|
||||||
|
|
||||||
return Container(
|
return SliderTile(
|
||||||
margin: const EdgeInsets.fromLTRB(0, 4, 0, 0),
|
key: ObjectKey(_contact),
|
||||||
clipBehavior: Clip.antiAlias,
|
disabled: _disabled,
|
||||||
decoration: ShapeDecoration(
|
selected: selected,
|
||||||
color: selected
|
tileScale: ScaleKind.secondary,
|
||||||
? scale.primaryScale.activeElementBackground
|
title: _contact.editedProfile.name,
|
||||||
: scale.primaryScale.hoverElementBackground,
|
subtitle: _contact.editedProfile.pronouns,
|
||||||
shape: RoundedRectangleBorder(
|
icon: Icons.chat,
|
||||||
borderRadius: BorderRadius.circular(8),
|
onTap: () {
|
||||||
)),
|
singleFuture(activeChatCubit, () async {
|
||||||
child: Slidable(
|
activeChatCubit.setActiveChat(remoteConversationRecordKey);
|
||||||
key: ObjectKey(_contact),
|
});
|
||||||
endActionPane: ActionPane(
|
},
|
||||||
motion: const DrawerMotion(),
|
endActions: [
|
||||||
children: [
|
SliderTileAction(
|
||||||
SlidableAction(
|
icon: Icons.delete,
|
||||||
onPressed: _disabled
|
label: translate('button.delete'),
|
||||||
? null
|
actionScale: ScaleKind.tertiary,
|
||||||
: (context) async {
|
onPressed: (context) async {
|
||||||
final chatListCubit = context.read<ChatListCubit>();
|
final chatListCubit = context.read<ChatListCubit>();
|
||||||
await chatListCubit.deleteChat(
|
await chatListCubit.deleteChat(
|
||||||
remoteConversationRecordKey:
|
remoteConversationRecordKey: remoteConversationRecordKey);
|
||||||
remoteConversationRecordKey);
|
})
|
||||||
},
|
],
|
||||||
backgroundColor: scale.tertiaryScale.background,
|
);
|
||||||
foregroundColor: scale.tertiaryScale.foregroundText,
|
|
||||||
icon: Icons.delete,
|
|
||||||
label: translate('button.delete'),
|
|
||||||
padding: const EdgeInsets.all(2)),
|
|
||||||
// SlidableAction(
|
|
||||||
// onPressed: (context) => (),
|
|
||||||
// backgroundColor: scale.secondaryScale.background,
|
|
||||||
// foregroundColor: scale.secondaryScale.text,
|
|
||||||
// icon: Icons.edit,
|
|
||||||
// label: 'Edit',
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
// The child of the Slidable is what the user sees when the
|
|
||||||
// component is not dragged.
|
|
||||||
child: ListTile(
|
|
||||||
onTap: _disabled
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
singleFuture(activeChatCubit, () async {
|
|
||||||
activeChatCubit
|
|
||||||
.setActiveChat(remoteConversationRecordKey);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
title: Text(_contact.editedProfile.name),
|
|
||||||
|
|
||||||
/// xxx show last message here
|
|
||||||
subtitle: (_contact.editedProfile.pronouns.isNotEmpty)
|
|
||||||
? Text(_contact.editedProfile.pronouns)
|
|
||||||
: null,
|
|
||||||
iconColor: selected
|
|
||||||
? scale.primaryScale.appText
|
|
||||||
: scale.primaryScale.subtleText,
|
|
||||||
textColor: selected
|
|
||||||
? scale.primaryScale.appText
|
|
||||||
: scale.primaryScale.subtleText,
|
|
||||||
selectedColor: scale.primaryScale.appText,
|
|
||||||
//Text(Timestamp.fromInt64(contactInvitationRecord.expiration) / ),
|
|
||||||
leading: const Icon(Icons.chat))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
||||||
super.debugFillProperties(properties);
|
|
||||||
properties.add(DiagnosticsProperty<proto.Contact>('contact', _contact));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import 'package:searchable_listview/searchable_listview.dart';
|
|||||||
|
|
||||||
import '../../contacts/contacts.dart';
|
import '../../contacts/contacts.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../tools/tools.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../chat_list.dart';
|
import '../chat_list.dart';
|
||||||
|
|
||||||
class ChatSingleContactListWidget extends StatelessWidget {
|
class ChatSingleContactListWidget extends StatelessWidget {
|
||||||
@ -41,8 +41,9 @@ class ChatSingleContactListWidget extends StatelessWidget {
|
|||||||
return const Text('...');
|
return const Text('...');
|
||||||
}
|
}
|
||||||
return ChatSingleContactItemWidget(
|
return ChatSingleContactItemWidget(
|
||||||
contact: contact,
|
contact: contact,
|
||||||
disabled: contactListV.busy);
|
disabled: contactListV.busy)
|
||||||
|
.paddingLTRB(0, 4, 0, 0);
|
||||||
},
|
},
|
||||||
filter: (value) {
|
filter: (value) {
|
||||||
final lowerValue = value.toLowerCase();
|
final lowerValue = value.toLowerCase();
|
||||||
|
@ -10,6 +10,7 @@ import 'package:flutter_translate/flutter_translate.dart';
|
|||||||
import 'package:qr_flutter/qr_flutter.dart';
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
import 'package:veilid_support/veilid_support.dart';
|
import 'package:veilid_support/veilid_support.dart';
|
||||||
|
|
||||||
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import '../contact_invitation.dart';
|
import '../contact_invitation.dart';
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.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_slidable/flutter_slidable.dart';
|
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
@ -28,99 +27,51 @@ class ContactInvitationItemWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
// final remoteConversationKey =
|
||||||
//final textTheme = theme.textTheme;
|
// contact.remoteConversationRecordKey.toVeilid();
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
|
||||||
|
|
||||||
return Container(
|
const selected =
|
||||||
clipBehavior: Clip.antiAlias,
|
false; // xxx: eventually when we have selectable invitations:
|
||||||
decoration: ShapeDecoration(
|
// activeContactCubit.state == remoteConversationRecordKey;
|
||||||
color: scale.tertiaryScale.subtleBorder,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
)),
|
|
||||||
child: Slidable(
|
|
||||||
// Specify a key if the Slidable is dismissible.
|
|
||||||
key: ObjectKey(contactInvitationRecord),
|
|
||||||
endActionPane: ActionPane(
|
|
||||||
// A motion is a widget used to control how the pane animates.
|
|
||||||
motion: const DrawerMotion(),
|
|
||||||
|
|
||||||
// A pane can dismiss the Slidable.
|
final tileDisabled =
|
||||||
//dismissible: DismissiblePane(onDismissed: () {}),
|
disabled || context.watch<ContactInvitationListCubit>().isBusy;
|
||||||
|
|
||||||
// All actions are defined in the children parameter.
|
return SliderTile(
|
||||||
children: [
|
key: ObjectKey(contactInvitationRecord),
|
||||||
// A SlidableAction can have an icon and/or a label.
|
disabled: tileDisabled,
|
||||||
SlidableAction(
|
selected: selected,
|
||||||
onPressed: disabled
|
tileScale: ScaleKind.primary,
|
||||||
? null
|
title: contactInvitationRecord.message.isEmpty
|
||||||
: (context) async {
|
? translate('contact_list.invitation')
|
||||||
final contactInvitationListCubit =
|
: contactInvitationRecord.message,
|
||||||
context.read<ContactInvitationListCubit>();
|
icon: Icons.person_add,
|
||||||
await contactInvitationListCubit.deleteInvitation(
|
onTap: () async {
|
||||||
accepted: false,
|
if (!context.mounted) {
|
||||||
contactRequestInboxRecordKey:
|
return;
|
||||||
contactInvitationRecord
|
}
|
||||||
.contactRequestInbox.recordKey
|
await ContactInvitationDisplayDialog.show(
|
||||||
.toVeilid());
|
context: context,
|
||||||
},
|
message: contactInvitationRecord.message,
|
||||||
backgroundColor: scale.tertiaryScale.background,
|
create: (context) => InvitationGeneratorCubit.value(
|
||||||
foregroundColor: scale.tertiaryScale.appText,
|
Uint8List.fromList(contactInvitationRecord.invitation)));
|
||||||
icon: Icons.delete,
|
},
|
||||||
label: translate('button.delete'),
|
endActions: [
|
||||||
padding: const EdgeInsets.all(2)),
|
SliderTileAction(
|
||||||
],
|
icon: Icons.delete,
|
||||||
),
|
label: translate('button.delete'),
|
||||||
|
actionScale: ScaleKind.tertiary,
|
||||||
// startActionPane: ActionPane(
|
onPressed: (context) async {
|
||||||
// motion: const DrawerMotion(),
|
final contactInvitationListCubit =
|
||||||
// children: [
|
context.read<ContactInvitationListCubit>();
|
||||||
// SlidableAction(
|
await contactInvitationListCubit.deleteInvitation(
|
||||||
// // An action can be bigger than the others.
|
accepted: false,
|
||||||
// flex: 2,
|
contactRequestInboxRecordKey: contactInvitationRecord
|
||||||
// onPressed: (context) => (),
|
.contactRequestInbox.recordKey
|
||||||
// backgroundColor: Color(0xFF7BC043),
|
.toVeilid());
|
||||||
// foregroundColor: Colors.white,
|
},
|
||||||
// icon: Icons.archive,
|
)
|
||||||
// label: 'Archive',
|
],
|
||||||
// ),
|
);
|
||||||
// SlidableAction(
|
|
||||||
// onPressed: (context) => (),
|
|
||||||
// backgroundColor: Color(0xFF0392CF),
|
|
||||||
// foregroundColor: Colors.white,
|
|
||||||
// icon: Icons.save,
|
|
||||||
// label: 'Save',
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// The child of the Slidable is what the user sees when the
|
|
||||||
// component is not dragged.
|
|
||||||
child: ListTile(
|
|
||||||
//title: Text(translate('contact_list.invitation')),
|
|
||||||
onTap: disabled
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
if (!context.mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await ContactInvitationDisplayDialog.show(
|
|
||||||
context: context,
|
|
||||||
message: contactInvitationRecord.message,
|
|
||||||
create: (context) => InvitationGeneratorCubit.value(
|
|
||||||
Uint8List.fromList(
|
|
||||||
contactInvitationRecord.invitation)));
|
|
||||||
},
|
|
||||||
title: Text(
|
|
||||||
contactInvitationRecord.message.isEmpty
|
|
||||||
? translate('contact_list.invitation')
|
|
||||||
: contactInvitationRecord.message,
|
|
||||||
softWrap: true,
|
|
||||||
),
|
|
||||||
iconColor: scale.tertiaryScale.background,
|
|
||||||
textColor: scale.tertiaryScale.appText,
|
|
||||||
//Text(Timestamp.fromInt64(contactInvitationRecord.expiration) / ),
|
|
||||||
leading: const Icon(Icons.person_add))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import 'package:flutter_translate/flutter_translate.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 '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import '../contact_invitation.dart';
|
import '../contact_invitation.dart';
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import 'package:veilid_support/veilid_support.dart';
|
|||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../contacts/contacts.dart';
|
import '../../contacts/contacts.dart';
|
||||||
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import '../contact_invitation.dart';
|
import '../contact_invitation.dart';
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
|
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
|
||||||
import 'create_invitation_dialog.dart';
|
import 'create_invitation_dialog.dart';
|
||||||
import 'paste_invitation_dialog.dart';
|
import 'paste_invitation_dialog.dart';
|
||||||
import 'scan_invitation_dialog.dart';
|
import 'scan_invitation_dialog.dart';
|
||||||
@ -37,7 +36,7 @@ Widget newContactBottomSheetBuilder(
|
|||||||
},
|
},
|
||||||
iconSize: 64,
|
iconSize: 64,
|
||||||
icon: const Icon(Icons.contact_page),
|
icon: const Icon(Icons.contact_page),
|
||||||
color: scale.primaryScale.background),
|
color: scale.primaryScale.hoverBorder),
|
||||||
Text(
|
Text(
|
||||||
translate('add_contact_sheet.create_invite'),
|
translate('add_contact_sheet.create_invite'),
|
||||||
)
|
)
|
||||||
@ -50,7 +49,7 @@ Widget newContactBottomSheetBuilder(
|
|||||||
},
|
},
|
||||||
iconSize: 64,
|
iconSize: 64,
|
||||||
icon: const Icon(Icons.qr_code_scanner),
|
icon: const Icon(Icons.qr_code_scanner),
|
||||||
color: scale.primaryScale.background),
|
color: scale.primaryScale.hoverBorder),
|
||||||
Text(
|
Text(
|
||||||
translate('add_contact_sheet.scan_invite'),
|
translate('add_contact_sheet.scan_invite'),
|
||||||
)
|
)
|
||||||
@ -63,7 +62,7 @@ Widget newContactBottomSheetBuilder(
|
|||||||
},
|
},
|
||||||
iconSize: 64,
|
iconSize: 64,
|
||||||
icon: const Icon(Icons.paste),
|
icon: const Icon(Icons.paste),
|
||||||
color: scale.primaryScale.background),
|
color: scale.primaryScale.hoverBorder),
|
||||||
Text(
|
Text(
|
||||||
translate('add_contact_sheet.paste_invite'),
|
translate('add_contact_sheet.paste_invite'),
|
||||||
)
|
)
|
||||||
|
@ -211,7 +211,7 @@ class ScanInvitationDialogState extends State<ScanInvitationDialog> {
|
|||||||
scale.grayScale.subtleBackground);
|
scale.grayScale.subtleBackground);
|
||||||
case TorchState.on:
|
case TorchState.on:
|
||||||
return Icon(Icons.flash_on,
|
return Icon(Icons.flash_on,
|
||||||
color: scale.primaryScale.background);
|
color: scale.primaryScale.primary);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -258,8 +258,8 @@ class ScanInvitationDialogState extends State<ScanInvitationDialog> {
|
|||||||
alignment: Alignment.topRight,
|
alignment: Alignment.topRight,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
icon: Icon(Icons.close,
|
icon:
|
||||||
color: scale.grayScale.background),
|
Icon(Icons.close, color: scale.grayScale.primary),
|
||||||
iconSize: 32,
|
iconSize: 32,
|
||||||
onPressed: () => {
|
onPressed: () => {
|
||||||
SchedulerBinding.instance
|
SchedulerBinding.instance
|
||||||
|
@ -2,7 +2,6 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
import 'package:flutter_translate/flutter_translate.dart';
|
||||||
import '../../chat_list/chat_list.dart';
|
import '../../chat_list/chat_list.dart';
|
||||||
import '../../layout/layout.dart';
|
import '../../layout/layout.dart';
|
||||||
@ -17,106 +16,65 @@ class ContactItemWidget extends StatelessWidget {
|
|||||||
final proto.Contact contact;
|
final proto.Contact contact;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty<proto.Contact>('contact', contact))
|
||||||
|
..add(DiagnosticsProperty<bool>('disabled', disabled));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(
|
Widget build(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
//final textTheme = theme.textTheme;
|
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
|
||||||
|
|
||||||
final remoteConversationKey =
|
final remoteConversationKey =
|
||||||
contact.remoteConversationRecordKey.toVeilid();
|
contact.remoteConversationRecordKey.toVeilid();
|
||||||
|
|
||||||
const selected = false; // xxx: eventually when we have selectable contacts:
|
const selected = false; // xxx: eventually when we have selectable contacts:
|
||||||
// activeContactCubit.state == remoteConversationRecordKey;
|
// activeContactCubit.state == remoteConversationRecordKey;
|
||||||
|
|
||||||
return Container(
|
final tileDisabled = disabled || context.watch<ContactListCubit>().isBusy;
|
||||||
margin: const EdgeInsets.fromLTRB(0, 4, 0, 0),
|
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
decoration: ShapeDecoration(
|
|
||||||
color: selected
|
|
||||||
// ignore: dead_code
|
|
||||||
? scale.primaryScale.activeElementBackground
|
|
||||||
: scale.primaryScale.hoverElementBackground,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
)),
|
|
||||||
child: Slidable(
|
|
||||||
key: ObjectKey(contact),
|
|
||||||
endActionPane: ActionPane(
|
|
||||||
motion: const DrawerMotion(),
|
|
||||||
children: [
|
|
||||||
SlidableAction(
|
|
||||||
onPressed: disabled || context.watch<ChatListCubit>().isBusy
|
|
||||||
? null
|
|
||||||
: (context) async {
|
|
||||||
final contactListCubit =
|
|
||||||
context.read<ContactListCubit>();
|
|
||||||
final chatListCubit = context.read<ChatListCubit>();
|
|
||||||
|
|
||||||
// Remove any chats for this contact
|
return SliderTile(
|
||||||
await chatListCubit.deleteChat(
|
key: ObjectKey(contact),
|
||||||
remoteConversationRecordKey:
|
disabled: tileDisabled,
|
||||||
remoteConversationKey);
|
selected: selected,
|
||||||
|
tileScale: ScaleKind.primary,
|
||||||
|
title: contact.editedProfile.name,
|
||||||
|
subtitle: contact.editedProfile.pronouns,
|
||||||
|
icon: Icons.person,
|
||||||
|
onTap: () async {
|
||||||
|
// Start a chat
|
||||||
|
final chatListCubit = context.read<ChatListCubit>();
|
||||||
|
|
||||||
// Delete the contact itself
|
await chatListCubit.getOrCreateChatSingleContact(
|
||||||
await contactListCubit.deleteContact(
|
remoteConversationRecordKey: remoteConversationKey);
|
||||||
contact: contact);
|
// Click over to chats
|
||||||
},
|
if (context.mounted) {
|
||||||
backgroundColor: scale.tertiaryScale.background,
|
await MainPager.of(context)
|
||||||
foregroundColor: scale.tertiaryScale.appText,
|
?.pageController
|
||||||
icon: Icons.delete,
|
.animateToPage(1, duration: 250.ms, curve: Curves.easeInOut);
|
||||||
label: translate('button.delete'),
|
}
|
||||||
padding: const EdgeInsets.all(2)),
|
},
|
||||||
// SlidableAction(
|
endActions: [
|
||||||
// onPressed: (context) => (),
|
SliderTileAction(
|
||||||
// backgroundColor: scale.secondaryScale.background,
|
icon: Icons.delete,
|
||||||
// foregroundColor: scale.secondaryScale.text,
|
label: translate('button.delete'),
|
||||||
// icon: Icons.edit,
|
actionScale: ScaleKind.tertiary,
|
||||||
// label: 'Edit',
|
onPressed: (context) async {
|
||||||
// ),
|
final contactListCubit = context.read<ContactListCubit>();
|
||||||
],
|
final chatListCubit = context.read<ChatListCubit>();
|
||||||
),
|
|
||||||
|
|
||||||
// The child of the Slidable is what the user sees when the
|
// Remove any chats for this contact
|
||||||
// component is not dragged.
|
await chatListCubit.deleteChat(
|
||||||
child: ListTile(
|
remoteConversationRecordKey: remoteConversationKey);
|
||||||
onTap: disabled || context.watch<ChatListCubit>().isBusy
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
// Start a chat
|
|
||||||
final chatListCubit = context.read<ChatListCubit>();
|
|
||||||
await chatListCubit.getOrCreateChatSingleContact(
|
|
||||||
remoteConversationRecordKey: remoteConversationKey);
|
|
||||||
// Click over to chats
|
|
||||||
if (context.mounted) {
|
|
||||||
await MainPager.of(context)
|
|
||||||
?.pageController
|
|
||||||
.animateToPage(1,
|
|
||||||
duration: 250.ms, curve: Curves.easeInOut);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: Text(contact.editedProfile.name),
|
|
||||||
subtitle: (contact.editedProfile.pronouns.isNotEmpty)
|
|
||||||
? Text(contact.editedProfile.pronouns)
|
|
||||||
: null,
|
|
||||||
iconColor: selected
|
|
||||||
// ignore: dead_code
|
|
||||||
? scale.primaryScale.appText
|
|
||||||
: scale.primaryScale.subtleText,
|
|
||||||
textColor: selected
|
|
||||||
// ignore: dead_code
|
|
||||||
? scale.primaryScale.appText
|
|
||||||
: scale.primaryScale.subtleText,
|
|
||||||
selectedColor: scale.primaryScale.appText,
|
|
||||||
leading: const Icon(Icons.person))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
// Delete the contact itself
|
||||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
await contactListCubit.deleteContact(contact: contact);
|
||||||
super.debugFillProperties(properties);
|
})
|
||||||
properties.add(DiagnosticsProperty<proto.Contact>('contact', contact));
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import 'package:flutter_translate/flutter_translate.dart';
|
|||||||
import 'package:searchable_listview/searchable_listview.dart';
|
import 'package:searchable_listview/searchable_listview.dart';
|
||||||
|
|
||||||
import '../../proto/proto.dart' as proto;
|
import '../../proto/proto.dart' as proto;
|
||||||
import '../../tools/tools.dart';
|
import '../../theme/theme.dart';
|
||||||
import 'contact_item_widget.dart';
|
import 'contact_item_widget.dart';
|
||||||
import 'empty_contact_list_widget.dart';
|
import 'empty_contact_list_widget.dart';
|
||||||
|
|
||||||
@ -25,33 +25,40 @@ class ContactListWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => SizedBox.expand(
|
Widget build(BuildContext context) {
|
||||||
child: styledTitleContainer(
|
final theme = Theme.of(context);
|
||||||
context: context,
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
title: translate('contact_list.title'),
|
|
||||||
child: SizedBox.expand(
|
return SizedBox.expand(
|
||||||
child: (contactList.isEmpty)
|
child: styledTitleContainer(
|
||||||
? const EmptyContactListWidget()
|
context: context,
|
||||||
: SearchableList<proto.Contact>(
|
title: translate('contact_list.title'),
|
||||||
initialList: contactList.toList(),
|
child: SizedBox.expand(
|
||||||
builder: (l, i, c) =>
|
child: (contactList.isEmpty)
|
||||||
ContactItemWidget(contact: c, disabled: disabled),
|
? const EmptyContactListWidget()
|
||||||
filter: (value) {
|
: SearchableList<proto.Contact>(
|
||||||
final lowerValue = value.toLowerCase();
|
initialList: contactList.toList(),
|
||||||
return contactList
|
builder: (l, i, c) =>
|
||||||
.where((element) =>
|
ContactItemWidget(contact: c, disabled: disabled)
|
||||||
element.editedProfile.name
|
.paddingLTRB(0, 4, 0, 0),
|
||||||
.toLowerCase()
|
filter: (value) {
|
||||||
.contains(lowerValue) ||
|
final lowerValue = value.toLowerCase();
|
||||||
element.editedProfile.pronouns
|
return contactList
|
||||||
.toLowerCase()
|
.where((element) =>
|
||||||
.contains(lowerValue))
|
element.editedProfile.name
|
||||||
.toList();
|
.toLowerCase()
|
||||||
},
|
.contains(lowerValue) ||
|
||||||
spaceBetweenSearchAndList: 4,
|
element.editedProfile.pronouns
|
||||||
inputDecoration: InputDecoration(
|
.toLowerCase()
|
||||||
labelText: translate('contact_list.search'),
|
.contains(lowerValue))
|
||||||
),
|
.toList();
|
||||||
).paddingAll(8),
|
},
|
||||||
))).paddingLTRB(8, 0, 8, 8);
|
spaceBetweenSearchAndList: 4,
|
||||||
|
defaultSuffixIconColor: scale.primaryScale.border,
|
||||||
|
inputDecoration: InputDecoration(
|
||||||
|
labelText: translate('contact_list.search'),
|
||||||
|
),
|
||||||
|
).paddingAll(8),
|
||||||
|
))).paddingLTRB(8, 0, 8, 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,11 @@ class _HomeAccountReadyMainState extends State<HomeAccountReadyMain> {
|
|||||||
Row(children: [
|
Row(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
color: scale.secondaryScale.appText,
|
color: scale.secondaryScale.borderText,
|
||||||
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor:
|
backgroundColor: MaterialStateProperty.all(
|
||||||
MaterialStateProperty.all(scale.secondaryScale.border),
|
scale.primaryScale.hoverBorder),
|
||||||
shape: MaterialStateProperty.all(
|
shape: MaterialStateProperty.all(
|
||||||
const RoundedRectangleBorder(
|
const RoundedRectangleBorder(
|
||||||
borderRadius:
|
borderRadius:
|
||||||
|
@ -11,7 +11,7 @@ import '../../../chat_list/chat_list.dart';
|
|||||||
import '../../../contact_invitation/contact_invitation.dart';
|
import '../../../contact_invitation/contact_invitation.dart';
|
||||||
import '../../../contacts/contacts.dart';
|
import '../../../contacts/contacts.dart';
|
||||||
import '../../../router/router.dart';
|
import '../../../router/router.dart';
|
||||||
import '../../../tools/tools.dart';
|
import '../../../theme/theme.dart';
|
||||||
|
|
||||||
class HomeAccountReadyShell extends StatefulWidget {
|
class HomeAccountReadyShell extends StatefulWidget {
|
||||||
factory HomeAccountReadyShell(
|
factory HomeAccountReadyShell(
|
||||||
|
@ -61,8 +61,9 @@ class AccountPageState extends State<AccountPage> {
|
|||||||
translate('account_page.contact_invitations'),
|
translate('account_page.contact_invitations'),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: textTheme.titleMedium!
|
style: textTheme.titleMedium!
|
||||||
.copyWith(color: scale.primaryScale.subtleText),
|
.copyWith(color: scale.primaryScale.borderText),
|
||||||
),
|
),
|
||||||
|
iconColor: scale.primaryScale.borderText,
|
||||||
initiallyExpanded: true,
|
initiallyExpanded: true,
|
||||||
children: [
|
children: [
|
||||||
ContactInvitationListWidget(
|
ContactInvitationListWidget(
|
||||||
|
@ -10,7 +10,6 @@ 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';
|
||||||
import '../../../../theme/theme.dart';
|
import '../../../../theme/theme.dart';
|
||||||
import '../../../../tools/tools.dart';
|
|
||||||
import 'account_page.dart';
|
import 'account_page.dart';
|
||||||
import 'bottom_sheet_action_button.dart';
|
import 'bottom_sheet_action_button.dart';
|
||||||
import 'chats_page.dart';
|
import 'chats_page.dart';
|
||||||
@ -41,7 +40,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
Icons.add_comment_sharp,
|
Icons.add_comment_sharp,
|
||||||
];
|
];
|
||||||
final _bottomLabelList = <String>[
|
final _bottomLabelList = <String>[
|
||||||
translate('pager.account'),
|
translate('pager.contacts'),
|
||||||
translate('pager.chats'),
|
translate('pager.chats'),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -82,12 +81,11 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
return BottomBarItem(
|
return BottomBarItem(
|
||||||
title: Text(_bottomLabelList[index]),
|
title: Text(_bottomLabelList[index]),
|
||||||
icon: Icon(_selectedIconList[index], color: scale.primaryScale.appText),
|
icon:
|
||||||
|
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
|
||||||
selectedIcon:
|
selectedIcon:
|
||||||
Icon(_selectedIconList[index], color: scale.primaryScale.appText),
|
Icon(_selectedIconList[index], color: scale.primaryScale.borderText),
|
||||||
backgroundColor: scale.primaryScale.appText,
|
backgroundColor: scale.primaryScale.borderText,
|
||||||
//unSelectedColor: theme.colorScheme.primaryContainer,
|
|
||||||
//selectedColor: theme.colorScheme.primary,
|
|
||||||
//badge: const Text('9+'),
|
//badge: const Text('9+'),
|
||||||
//showBadge: true,
|
//showBadge: true,
|
||||||
);
|
);
|
||||||
@ -169,21 +167,10 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
// ),
|
// ),
|
||||||
bottomNavigationBar: StylishBottomBar(
|
bottomNavigationBar: StylishBottomBar(
|
||||||
backgroundColor: scale.primaryScale.hoverBorder,
|
backgroundColor: scale.primaryScale.hoverBorder,
|
||||||
// gradient: LinearGradient(
|
|
||||||
// begin: Alignment.topCenter,
|
|
||||||
// end: Alignment.bottomCenter,
|
|
||||||
// colors: <Color>[
|
|
||||||
// theme.colorScheme.primary,
|
|
||||||
// theme.colorScheme.primaryContainer,
|
|
||||||
// ]),
|
|
||||||
//borderRadius: BorderRadius.all(Radius.circular(16)),
|
|
||||||
option: AnimatedBarOptions(
|
option: AnimatedBarOptions(
|
||||||
// iconSize: 32,
|
|
||||||
//barAnimation: BarAnimation.fade,
|
|
||||||
iconStyle: IconStyle.animated,
|
|
||||||
inkEffect: true,
|
inkEffect: true,
|
||||||
inkColor: scale.primaryScale.hoverBackground,
|
inkColor: scale.primaryScale.hoverPrimary,
|
||||||
//opacity: 0.3,
|
opacity: 0.3,
|
||||||
),
|
),
|
||||||
items: _buildBottomBarItems(),
|
items: _buildBottomBarItems(),
|
||||||
hasNotch: true,
|
hasNotch: true,
|
||||||
@ -198,11 +185,11 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
floatingActionButton: BottomSheetActionButton(
|
floatingActionButton: BottomSheetActionButton(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14))),
|
borderRadius: BorderRadius.all(Radius.circular(14))),
|
||||||
foregroundColor: scale.secondaryScale.appText,
|
foregroundColor: scale.secondaryScale.borderText,
|
||||||
backgroundColor: scale.secondaryScale.hoverBorder,
|
backgroundColor: scale.secondaryScale.hoverBorder,
|
||||||
builder: (context) => Icon(
|
builder: (context) => Icon(
|
||||||
_fabIconList[_currentPage],
|
_fabIconList[_currentPage],
|
||||||
color: scale.secondaryScale.appText,
|
color: scale.secondaryScale.borderText,
|
||||||
),
|
),
|
||||||
bottomSheetBuilder: (sheetContext) =>
|
bottomSheetBuilder: (sheetContext) =>
|
||||||
_bottomSheetBuilder(sheetContext, context)),
|
_bottomSheetBuilder(sheetContext, context)),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../tools/tools.dart';
|
import '../../theme/theme.dart';
|
||||||
|
|
||||||
class HomeNoActive extends StatefulWidget {
|
class HomeNoActive extends StatefulWidget {
|
||||||
const HomeNoActive({super.key});
|
const HomeNoActive({super.key});
|
||||||
|
54
lib/theme/models/chat_theme.dart
Normal file
54
lib/theme/models/chat_theme.dart
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
|
||||||
|
|
||||||
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
|
ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) =>
|
||||||
|
DefaultChatTheme(
|
||||||
|
primaryColor: scale.primaryScale.calloutBackground,
|
||||||
|
secondaryColor: scale.secondaryScale.calloutBackground,
|
||||||
|
backgroundColor: scale.grayScale.appBackground,
|
||||||
|
sendButtonIcon: Image.asset(
|
||||||
|
'assets/icon-send.png',
|
||||||
|
color: scale.primaryScale.borderText,
|
||||||
|
package: 'flutter_chat_ui',
|
||||||
|
),
|
||||||
|
inputBackgroundColor: Colors.blue,
|
||||||
|
inputBorderRadius: BorderRadius.zero,
|
||||||
|
inputTextDecoration: InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
fillColor: scale.primaryScale.elementBackground,
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderSide: BorderSide.none,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8))),
|
||||||
|
focusedBorder: const OutlineInputBorder(
|
||||||
|
borderSide: BorderSide.none,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8))),
|
||||||
|
),
|
||||||
|
inputContainerDecoration:
|
||||||
|
BoxDecoration(color: scale.primaryScale.border),
|
||||||
|
inputPadding: const EdgeInsets.all(9),
|
||||||
|
inputTextColor: scale.primaryScale.appText,
|
||||||
|
attachmentButtonIcon: const Icon(Icons.attach_file),
|
||||||
|
sentMessageBodyTextStyle: TextStyle(
|
||||||
|
color: scale.primaryScale.calloutText,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
height: 1.5,
|
||||||
|
),
|
||||||
|
sentEmojiMessageTextStyle: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 64,
|
||||||
|
),
|
||||||
|
receivedMessageBodyTextStyle: TextStyle(
|
||||||
|
color: scale.secondaryScale.calloutText,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
height: 1.5,
|
||||||
|
),
|
||||||
|
receivedEmojiMessageTextStyle: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 64,
|
||||||
|
));
|
83
lib/theme/models/contrast_generator.dart
Normal file
83
lib/theme/models/contrast_generator.dart
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'radix_generator.dart';
|
||||||
|
import 'scale_color.dart';
|
||||||
|
import 'scale_input_decorator_theme.dart';
|
||||||
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
|
ScaleScheme _contrastScale(Brightness brightness) {
|
||||||
|
final back = brightness == Brightness.light ? Colors.white : Colors.black;
|
||||||
|
final front = brightness == Brightness.light ? Colors.black : Colors.white;
|
||||||
|
|
||||||
|
final primaryScale = ScaleColor(
|
||||||
|
appBackground: back,
|
||||||
|
subtleBackground: back,
|
||||||
|
elementBackground: back,
|
||||||
|
hoverElementBackground: back,
|
||||||
|
activeElementBackground: back,
|
||||||
|
subtleBorder: front,
|
||||||
|
border: front,
|
||||||
|
hoverBorder: front,
|
||||||
|
primary: back,
|
||||||
|
hoverPrimary: back,
|
||||||
|
subtleText: front,
|
||||||
|
appText: front,
|
||||||
|
primaryText: front,
|
||||||
|
borderText: back,
|
||||||
|
dialogBorder: front,
|
||||||
|
calloutBackground: front,
|
||||||
|
calloutText: back,
|
||||||
|
);
|
||||||
|
|
||||||
|
return ScaleScheme(
|
||||||
|
primaryScale: primaryScale,
|
||||||
|
primaryAlphaScale: primaryScale,
|
||||||
|
secondaryScale: primaryScale,
|
||||||
|
tertiaryScale: primaryScale,
|
||||||
|
grayScale: primaryScale,
|
||||||
|
errorScale: primaryScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeData contrastGenerator(Brightness brightness) {
|
||||||
|
final textTheme = makeRadixTextTheme(brightness);
|
||||||
|
final scaleScheme = _contrastScale(brightness);
|
||||||
|
final colorScheme = scaleScheme.toColorScheme(brightness);
|
||||||
|
final scaleConfig = ScaleConfig(useVisualIndicators: true);
|
||||||
|
|
||||||
|
final themeData = ThemeData.from(
|
||||||
|
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
||||||
|
return themeData.copyWith(
|
||||||
|
bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
|
||||||
|
elevation: 0,
|
||||||
|
modalElevation: 0,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(16),
|
||||||
|
topRight: Radius.circular(16)))),
|
||||||
|
canvasColor: scaleScheme.primaryScale.subtleBackground,
|
||||||
|
chipTheme: themeData.chipTheme.copyWith(
|
||||||
|
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
||||||
|
selectedColor: scaleScheme.primaryScale.activeElementBackground,
|
||||||
|
surfaceTintColor: scaleScheme.primaryScale.hoverElementBackground,
|
||||||
|
checkmarkColor: scaleScheme.primaryScale.border,
|
||||||
|
side: BorderSide(color: scaleScheme.primaryScale.border)),
|
||||||
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
||||||
|
foregroundColor: scaleScheme.primaryScale.appText,
|
||||||
|
disabledBackgroundColor: scaleScheme.grayScale.elementBackground,
|
||||||
|
disabledForegroundColor: scaleScheme.grayScale.appText,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: BorderSide(color: scaleScheme.primaryScale.border),
|
||||||
|
borderRadius: BorderRadius.circular(8))),
|
||||||
|
),
|
||||||
|
textSelectionTheme: TextSelectionThemeData(
|
||||||
|
cursorColor: scaleScheme.primaryScale.appText,
|
||||||
|
selectionColor: scaleScheme.primaryScale.appText.withAlpha(0x7F),
|
||||||
|
selectionHandleColor: scaleScheme.primaryScale.appText),
|
||||||
|
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme),
|
||||||
|
extensions: <ThemeExtension<dynamic>>[
|
||||||
|
scaleScheme,
|
||||||
|
scaleConfig,
|
||||||
|
]);
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
|
export 'chat_theme.dart';
|
||||||
export 'radix_generator.dart';
|
export 'radix_generator.dart';
|
||||||
export 'scale_color.dart';
|
export 'scale_color.dart';
|
||||||
export 'scale_scheme.dart';
|
export 'scale_scheme.dart';
|
||||||
|
export 'slider_tile.dart';
|
||||||
export 'theme_preference.dart';
|
export 'theme_preference.dart';
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
|
|
||||||
import 'package:radix_colors/radix_colors.dart';
|
import 'package:radix_colors/radix_colors.dart';
|
||||||
|
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
import 'scale_color.dart';
|
import 'scale_color.dart';
|
||||||
|
import 'scale_input_decorator_theme.dart';
|
||||||
import 'scale_scheme.dart';
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
enum RadixThemeColor {
|
enum RadixThemeColor {
|
||||||
scarlet, // tomato + red + violet
|
scarlet, // red + violet + tomato
|
||||||
babydoll, // crimson + purple + pink
|
babydoll, // crimson + pink + purple
|
||||||
vapor, // pink + cyan + plum
|
vapor, // pink + cyan + plum
|
||||||
gold, // yellow + amber + orange
|
gold, // yellow + amber + orange
|
||||||
garden, // grass + orange + brown
|
garden, // grass + orange + brown
|
||||||
@ -19,7 +19,7 @@ enum RadixThemeColor {
|
|||||||
lapis, // blue + indigo + mint
|
lapis, // blue + indigo + mint
|
||||||
eggplant, // violet + purple + indigo
|
eggplant, // violet + purple + indigo
|
||||||
lime, // lime + yellow + orange
|
lime, // lime + yellow + orange
|
||||||
grim, // mauve + slate + sage
|
grim, // grey + purple + brown
|
||||||
}
|
}
|
||||||
|
|
||||||
enum _RadixBaseColor {
|
enum _RadixBaseColor {
|
||||||
@ -282,11 +282,15 @@ extension ToScaleColor on RadixColor {
|
|||||||
subtleBorder: step6,
|
subtleBorder: step6,
|
||||||
border: step7,
|
border: step7,
|
||||||
hoverBorder: step8,
|
hoverBorder: step8,
|
||||||
background: step9,
|
primary: step9,
|
||||||
hoverBackground: step10,
|
hoverPrimary: step10,
|
||||||
subtleText: step11,
|
subtleText: step11,
|
||||||
appText: step12,
|
appText: step12,
|
||||||
foregroundText: scaleExtra.foregroundText,
|
primaryText: scaleExtra.foregroundText,
|
||||||
|
borderText: step12,
|
||||||
|
dialogBorder: step9,
|
||||||
|
calloutBackground: step9,
|
||||||
|
calloutText: scaleExtra.foregroundText,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,28 +342,27 @@ class RadixScheme {
|
|||||||
RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
|
RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
|
||||||
late RadixScheme radixScheme;
|
late RadixScheme radixScheme;
|
||||||
switch (themeColor) {
|
switch (themeColor) {
|
||||||
// tomato + red + violet
|
// red + violet + tomato
|
||||||
case RadixThemeColor.scarlet:
|
case RadixThemeColor.scarlet:
|
||||||
radixScheme = RadixScheme(
|
radixScheme = RadixScheme(
|
||||||
primaryScale:
|
primaryScale: _radixColorSteps(brightness, false, _RadixBaseColor.red),
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.tomato),
|
|
||||||
primaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
primaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
primaryAlphaScale:
|
primaryAlphaScale:
|
||||||
_radixColorSteps(brightness, true, _RadixBaseColor.tomato),
|
_radixColorSteps(brightness, true, _RadixBaseColor.red),
|
||||||
primaryAlphaExtra: RadixScaleExtra(foregroundText: Colors.white),
|
primaryAlphaExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
secondaryScale:
|
secondaryScale:
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.red),
|
_radixColorSteps(brightness, false, _RadixBaseColor.violet),
|
||||||
secondaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
secondaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
tertiaryScale:
|
tertiaryScale:
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.violet),
|
_radixColorSteps(brightness, false, _RadixBaseColor.tomato),
|
||||||
tertiaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
tertiaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.tomato),
|
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.red),
|
||||||
grayExtra: RadixScaleExtra(foregroundText: Colors.white),
|
grayExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
errorScale: _radixColorSteps(brightness, false, _RadixBaseColor.yellow),
|
errorScale: _radixColorSteps(brightness, false, _RadixBaseColor.yellow),
|
||||||
errorExtra: RadixScaleExtra(foregroundText: Colors.black),
|
errorExtra: RadixScaleExtra(foregroundText: Colors.black),
|
||||||
);
|
);
|
||||||
|
|
||||||
// crimson + purple + pink
|
// crimson + pink + purple
|
||||||
case RadixThemeColor.babydoll:
|
case RadixThemeColor.babydoll:
|
||||||
radixScheme = RadixScheme(
|
radixScheme = RadixScheme(
|
||||||
primaryScale:
|
primaryScale:
|
||||||
@ -369,10 +372,10 @@ RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
|
|||||||
_radixColorSteps(brightness, true, _RadixBaseColor.crimson),
|
_radixColorSteps(brightness, true, _RadixBaseColor.crimson),
|
||||||
primaryAlphaExtra: RadixScaleExtra(foregroundText: Colors.white),
|
primaryAlphaExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
secondaryScale:
|
secondaryScale:
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.purple),
|
_radixColorSteps(brightness, false, _RadixBaseColor.pink),
|
||||||
secondaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
secondaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
tertiaryScale:
|
tertiaryScale:
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.pink),
|
_radixColorSteps(brightness, false, _RadixBaseColor.purple),
|
||||||
tertiaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
tertiaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
grayScale:
|
grayScale:
|
||||||
_radixGraySteps(brightness, false, _RadixBaseColor.crimson),
|
_radixGraySteps(brightness, false, _RadixBaseColor.crimson),
|
||||||
@ -546,13 +549,13 @@ RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
|
|||||||
_radixGraySteps(brightness, false, _RadixBaseColor.tomato),
|
_radixGraySteps(brightness, false, _RadixBaseColor.tomato),
|
||||||
primaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
primaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
primaryAlphaScale:
|
primaryAlphaScale:
|
||||||
_radixColorSteps(brightness, true, _RadixBaseColor.tomato),
|
_radixGraySteps(brightness, true, _RadixBaseColor.tomato),
|
||||||
primaryAlphaExtra: RadixScaleExtra(foregroundText: Colors.white),
|
primaryAlphaExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
secondaryScale:
|
secondaryScale:
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.indigo),
|
_radixColorSteps(brightness, false, _RadixBaseColor.purple),
|
||||||
secondaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
secondaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
tertiaryScale:
|
tertiaryScale:
|
||||||
_radixColorSteps(brightness, false, _RadixBaseColor.teal),
|
_radixColorSteps(brightness, false, _RadixBaseColor.brown),
|
||||||
tertiaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
tertiaryExtra: RadixScaleExtra(foregroundText: Colors.white),
|
||||||
grayScale: brightness == Brightness.dark
|
grayScale: brightness == Brightness.dark
|
||||||
? RadixColors.dark.gray
|
? RadixColors.dark.gray
|
||||||
@ -565,87 +568,7 @@ RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
|
|||||||
return radixScheme;
|
return radixScheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorScheme _scaleToColorScheme(Brightness brightness, ScaleScheme scale) =>
|
TextTheme makeRadixTextTheme(Brightness brightness) {
|
||||||
ColorScheme(
|
|
||||||
brightness: brightness,
|
|
||||||
primary: scale.primaryScale.background, // reviewed
|
|
||||||
onPrimary: scale.primaryScale.foregroundText, // reviewed
|
|
||||||
primaryContainer:
|
|
||||||
Colors.red, // scale.primaryScale.hoverElementBackground,
|
|
||||||
onPrimaryContainer: Colors.green, //scale.primaryScale.subtleText,
|
|
||||||
secondary: scale.secondaryScale.background,
|
|
||||||
onSecondary: scale.secondaryScale.foregroundText,
|
|
||||||
secondaryContainer: scale.secondaryScale.hoverElementBackground,
|
|
||||||
onSecondaryContainer: scale.secondaryScale.subtleText,
|
|
||||||
tertiary: scale.tertiaryScale.background,
|
|
||||||
onTertiary: scale.tertiaryScale.foregroundText,
|
|
||||||
tertiaryContainer: scale.tertiaryScale.hoverElementBackground,
|
|
||||||
onTertiaryContainer: scale.tertiaryScale.subtleText,
|
|
||||||
error: scale.errorScale.background,
|
|
||||||
onError: scale.errorScale.foregroundText,
|
|
||||||
errorContainer: scale.errorScale.hoverElementBackground,
|
|
||||||
onErrorContainer: scale.errorScale.subtleText,
|
|
||||||
background: scale.grayScale.appBackground, // reviewed
|
|
||||||
onBackground: scale.grayScale.appText, // reviewed
|
|
||||||
surface: scale.primaryScale.background, // reviewed
|
|
||||||
onSurface: scale.primaryScale.foregroundText, // reviewed
|
|
||||||
surfaceVariant: scale.primaryScale.elementBackground,
|
|
||||||
onSurfaceVariant:
|
|
||||||
scale.primaryScale.foregroundText, // ?? reviewed a little
|
|
||||||
outline: scale.primaryScale.border,
|
|
||||||
outlineVariant: scale.primaryScale.subtleBorder,
|
|
||||||
shadow: const Color(0xFF000000),
|
|
||||||
scrim: scale.primaryScale.background,
|
|
||||||
inverseSurface: scale.primaryScale.subtleText,
|
|
||||||
onInverseSurface: scale.primaryScale.subtleBackground,
|
|
||||||
inversePrimary: scale.primaryScale.hoverBackground,
|
|
||||||
surfaceTint: scale.primaryAlphaScale.hoverElementBackground,
|
|
||||||
);
|
|
||||||
|
|
||||||
ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) =>
|
|
||||||
DefaultChatTheme(
|
|
||||||
primaryColor: scale.primaryScale.background,
|
|
||||||
secondaryColor: scale.secondaryScale.background,
|
|
||||||
backgroundColor: scale.grayScale.appBackground,
|
|
||||||
inputBackgroundColor: Colors.blue,
|
|
||||||
inputBorderRadius: BorderRadius.zero,
|
|
||||||
inputTextDecoration: InputDecoration(
|
|
||||||
filled: true,
|
|
||||||
fillColor: scale.primaryScale.elementBackground,
|
|
||||||
isDense: true,
|
|
||||||
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
|
||||||
border: const OutlineInputBorder(
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8))),
|
|
||||||
),
|
|
||||||
inputContainerDecoration:
|
|
||||||
BoxDecoration(color: scale.primaryScale.border),
|
|
||||||
inputPadding: const EdgeInsets.all(9),
|
|
||||||
inputTextColor: scale.primaryScale.appText,
|
|
||||||
attachmentButtonIcon: const Icon(Icons.attach_file),
|
|
||||||
sentMessageBodyTextStyle: TextStyle(
|
|
||||||
color: scale.primaryScale.foregroundText,
|
|
||||||
decorationColor: Colors.red,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
height: 1.5,
|
|
||||||
),
|
|
||||||
sentEmojiMessageTextStyle: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 64,
|
|
||||||
),
|
|
||||||
receivedMessageBodyTextStyle: TextStyle(
|
|
||||||
color: scale.primaryScale.foregroundText,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
height: 1.5,
|
|
||||||
),
|
|
||||||
receivedEmojiMessageTextStyle: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 64,
|
|
||||||
));
|
|
||||||
|
|
||||||
TextTheme _makeTextTheme(Brightness brightness) {
|
|
||||||
late final TextTheme textTheme;
|
late final TextTheme textTheme;
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
textTheme = (brightness == Brightness.light)
|
textTheme = (brightness == Brightness.light)
|
||||||
@ -677,10 +600,11 @@ TextTheme _makeTextTheme(Brightness brightness) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
||||||
final textTheme = _makeTextTheme(brightness);
|
final textTheme = makeRadixTextTheme(brightness);
|
||||||
final radix = _radixScheme(brightness, themeColor);
|
final radix = _radixScheme(brightness, themeColor);
|
||||||
final scaleScheme = radix.toScale();
|
final scaleScheme = radix.toScale();
|
||||||
final colorScheme = _scaleToColorScheme(brightness, scaleScheme);
|
final colorScheme = scaleScheme.toColorScheme(brightness);
|
||||||
|
final scaleConfig = ScaleConfig(useVisualIndicators: false);
|
||||||
|
|
||||||
final themeData = ThemeData.from(
|
final themeData = ThemeData.from(
|
||||||
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
|
||||||
@ -697,34 +621,18 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
|||||||
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
||||||
selectedColor: scaleScheme.primaryScale.activeElementBackground,
|
selectedColor: scaleScheme.primaryScale.activeElementBackground,
|
||||||
surfaceTintColor: scaleScheme.primaryScale.hoverElementBackground,
|
surfaceTintColor: scaleScheme.primaryScale.hoverElementBackground,
|
||||||
checkmarkColor: scaleScheme.primaryScale.background,
|
checkmarkColor: scaleScheme.primaryScale.primary,
|
||||||
side: BorderSide(color: scaleScheme.primaryScale.border)),
|
side: BorderSide(color: scaleScheme.primaryScale.border)),
|
||||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
backgroundColor: scaleScheme.primaryScale.elementBackground,
|
||||||
foregroundColor: scaleScheme.primaryScale.appText,
|
foregroundColor: scaleScheme.primaryScale.primary,
|
||||||
disabledBackgroundColor: scaleScheme.grayScale.elementBackground,
|
disabledBackgroundColor: scaleScheme.grayScale.elementBackground,
|
||||||
disabledForegroundColor: scaleScheme.grayScale.appText,
|
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))),
|
||||||
),
|
),
|
||||||
focusColor: scaleScheme.primaryScale.activeElementBackground,
|
inputDecorationTheme: ScaleInputDecoratorTheme(scaleScheme, textTheme),
|
||||||
hoverColor: scaleScheme.primaryScale.hoverElementBackground,
|
extensions: <ThemeExtension<dynamic>>[scaleScheme, scaleConfig]);
|
||||||
inputDecorationTheme: themeData.inputDecorationTheme.copyWith(
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(color: scaleScheme.primaryScale.border),
|
|
||||||
borderRadius: BorderRadius.circular(8)),
|
|
||||||
contentPadding: const EdgeInsets.all(8),
|
|
||||||
labelStyle: TextStyle(
|
|
||||||
color: scaleScheme.primaryScale.subtleText.withAlpha(127)),
|
|
||||||
floatingLabelStyle:
|
|
||||||
TextStyle(color: scaleScheme.primaryScale.subtleText),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: scaleScheme.primaryScale.hoverBorder, width: 2),
|
|
||||||
borderRadius: BorderRadius.circular(8))),
|
|
||||||
extensions: <ThemeExtension<dynamic>>[
|
|
||||||
scaleScheme,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,15 @@ class ScaleColor {
|
|||||||
required this.subtleBorder,
|
required this.subtleBorder,
|
||||||
required this.border,
|
required this.border,
|
||||||
required this.hoverBorder,
|
required this.hoverBorder,
|
||||||
required this.background,
|
required this.primary,
|
||||||
required this.hoverBackground,
|
required this.hoverPrimary,
|
||||||
required this.subtleText,
|
required this.subtleText,
|
||||||
required this.appText,
|
required this.appText,
|
||||||
required this.foregroundText,
|
required this.primaryText,
|
||||||
|
required this.borderText,
|
||||||
|
required this.dialogBorder,
|
||||||
|
required this.calloutBackground,
|
||||||
|
required this.calloutText,
|
||||||
});
|
});
|
||||||
|
|
||||||
Color appBackground;
|
Color appBackground;
|
||||||
@ -25,11 +29,15 @@ class ScaleColor {
|
|||||||
Color subtleBorder;
|
Color subtleBorder;
|
||||||
Color border;
|
Color border;
|
||||||
Color hoverBorder;
|
Color hoverBorder;
|
||||||
Color background;
|
Color primary;
|
||||||
Color hoverBackground;
|
Color hoverPrimary;
|
||||||
Color subtleText;
|
Color subtleText;
|
||||||
Color appText;
|
Color appText;
|
||||||
Color foregroundText;
|
Color primaryText;
|
||||||
|
Color borderText;
|
||||||
|
Color dialogBorder;
|
||||||
|
Color calloutBackground;
|
||||||
|
Color calloutText;
|
||||||
|
|
||||||
ScaleColor copyWith({
|
ScaleColor copyWith({
|
||||||
Color? appBackground,
|
Color? appBackground,
|
||||||
@ -45,24 +53,31 @@ class ScaleColor {
|
|||||||
Color? subtleText,
|
Color? subtleText,
|
||||||
Color? appText,
|
Color? appText,
|
||||||
Color? foregroundText,
|
Color? foregroundText,
|
||||||
|
Color? borderText,
|
||||||
|
Color? dialogBorder,
|
||||||
|
Color? calloutBackground,
|
||||||
|
Color? calloutText,
|
||||||
}) =>
|
}) =>
|
||||||
ScaleColor(
|
ScaleColor(
|
||||||
appBackground: appBackground ?? this.appBackground,
|
appBackground: appBackground ?? this.appBackground,
|
||||||
subtleBackground: subtleBackground ?? this.subtleBackground,
|
subtleBackground: subtleBackground ?? this.subtleBackground,
|
||||||
elementBackground: elementBackground ?? this.elementBackground,
|
elementBackground: elementBackground ?? this.elementBackground,
|
||||||
hoverElementBackground:
|
hoverElementBackground:
|
||||||
hoverElementBackground ?? this.hoverElementBackground,
|
hoverElementBackground ?? this.hoverElementBackground,
|
||||||
activeElementBackground:
|
activeElementBackground:
|
||||||
activeElementBackground ?? this.activeElementBackground,
|
activeElementBackground ?? this.activeElementBackground,
|
||||||
subtleBorder: subtleBorder ?? this.subtleBorder,
|
subtleBorder: subtleBorder ?? this.subtleBorder,
|
||||||
border: border ?? this.border,
|
border: border ?? this.border,
|
||||||
hoverBorder: hoverBorder ?? this.hoverBorder,
|
hoverBorder: hoverBorder ?? this.hoverBorder,
|
||||||
background: background ?? this.background,
|
primary: background ?? this.primary,
|
||||||
hoverBackground: hoverBackground ?? this.hoverBackground,
|
hoverPrimary: hoverBackground ?? this.hoverPrimary,
|
||||||
subtleText: subtleText ?? this.subtleText,
|
subtleText: subtleText ?? this.subtleText,
|
||||||
appText: appText ?? this.appText,
|
appText: appText ?? this.appText,
|
||||||
foregroundText: foregroundText ?? this.foregroundText,
|
primaryText: foregroundText ?? this.primaryText,
|
||||||
);
|
borderText: borderText ?? this.borderText,
|
||||||
|
dialogBorder: dialogBorder ?? this.dialogBorder,
|
||||||
|
calloutBackground: calloutBackground ?? this.calloutBackground,
|
||||||
|
calloutText: calloutText ?? this.calloutText);
|
||||||
|
|
||||||
// ignore: prefer_constructors_over_static_methods
|
// ignore: prefer_constructors_over_static_methods
|
||||||
static ScaleColor lerp(ScaleColor a, ScaleColor b, double t) => ScaleColor(
|
static ScaleColor lerp(ScaleColor a, ScaleColor b, double t) => ScaleColor(
|
||||||
@ -85,14 +100,22 @@ class ScaleColor {
|
|||||||
border: Color.lerp(a.border, b.border, t) ?? const Color(0x00000000),
|
border: Color.lerp(a.border, b.border, t) ?? const Color(0x00000000),
|
||||||
hoverBorder: Color.lerp(a.hoverBorder, b.hoverBorder, t) ??
|
hoverBorder: Color.lerp(a.hoverBorder, b.hoverBorder, t) ??
|
||||||
const Color(0x00000000),
|
const Color(0x00000000),
|
||||||
background: Color.lerp(a.background, b.background, t) ??
|
primary: Color.lerp(a.primary, b.primary, t) ?? const Color(0x00000000),
|
||||||
const Color(0x00000000),
|
hoverPrimary: Color.lerp(a.hoverPrimary, b.hoverPrimary, t) ??
|
||||||
hoverBackground: Color.lerp(a.hoverBackground, b.hoverBackground, t) ??
|
|
||||||
const Color(0x00000000),
|
const Color(0x00000000),
|
||||||
subtleText: Color.lerp(a.subtleText, b.subtleText, t) ??
|
subtleText: Color.lerp(a.subtleText, b.subtleText, t) ??
|
||||||
const Color(0x00000000),
|
const Color(0x00000000),
|
||||||
appText: Color.lerp(a.appText, b.appText, t) ?? const Color(0x00000000),
|
appText: Color.lerp(a.appText, b.appText, t) ?? const Color(0x00000000),
|
||||||
foregroundText: Color.lerp(a.foregroundText, b.foregroundText, t) ??
|
primaryText: Color.lerp(a.primaryText, b.primaryText, t) ??
|
||||||
|
const Color(0x00000000),
|
||||||
|
borderText: Color.lerp(a.borderText, b.borderText, t) ??
|
||||||
|
const Color(0x00000000),
|
||||||
|
dialogBorder: Color.lerp(a.dialogBorder, b.dialogBorder, t) ??
|
||||||
|
const Color(0x00000000),
|
||||||
|
calloutBackground:
|
||||||
|
Color.lerp(a.calloutBackground, b.calloutBackground, t) ??
|
||||||
|
const Color(0x00000000),
|
||||||
|
calloutText: Color.lerp(a.calloutText, b.calloutText, t) ??
|
||||||
const Color(0x00000000),
|
const Color(0x00000000),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
165
lib/theme/models/scale_input_decorator_theme.dart
Normal file
165
lib/theme/models/scale_input_decorator_theme.dart
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'scale_scheme.dart';
|
||||||
|
|
||||||
|
class ScaleInputDecoratorTheme extends InputDecorationTheme {
|
||||||
|
ScaleInputDecoratorTheme(this._scaleScheme, this._textTheme)
|
||||||
|
: super(
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: _scaleScheme.primaryScale.border),
|
||||||
|
borderRadius: BorderRadius.circular(8)),
|
||||||
|
contentPadding: const EdgeInsets.all(8),
|
||||||
|
labelStyle: TextStyle(
|
||||||
|
color: _scaleScheme.primaryScale.subtleText.withAlpha(127)),
|
||||||
|
floatingLabelStyle:
|
||||||
|
TextStyle(color: _scaleScheme.primaryScale.subtleText),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: _scaleScheme.primaryScale.hoverBorder, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(8)));
|
||||||
|
|
||||||
|
final ScaleScheme _scaleScheme;
|
||||||
|
final TextTheme _textTheme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((states) {
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return TextStyle(color: _scaleScheme.grayScale.border);
|
||||||
|
}
|
||||||
|
return TextStyle(color: _scaleScheme.primaryScale.border);
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get fillColor => MaterialStateColor.resolveWith((states) {
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return _scaleScheme.grayScale.primary.withOpacity(0.04);
|
||||||
|
}
|
||||||
|
return _scaleScheme.primaryScale.primary.withOpacity(0.04);
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
BorderSide? get activeIndicatorBorder =>
|
||||||
|
MaterialStateBorderSide.resolveWith((states) {
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return BorderSide(
|
||||||
|
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.error)) {
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return BorderSide(color: _scaleScheme.errorScale.hoverBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return BorderSide(color: _scaleScheme.errorScale.border, width: 2);
|
||||||
|
}
|
||||||
|
return BorderSide(color: _scaleScheme.errorScale.subtleBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return BorderSide(color: _scaleScheme.secondaryScale.hoverBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return BorderSide(
|
||||||
|
color: _scaleScheme.secondaryScale.border, width: 2);
|
||||||
|
}
|
||||||
|
return BorderSide(color: _scaleScheme.secondaryScale.subtleBorder);
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
BorderSide? get outlineBorder =>
|
||||||
|
MaterialStateBorderSide.resolveWith((states) {
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return BorderSide(
|
||||||
|
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.error)) {
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return BorderSide(color: _scaleScheme.errorScale.hoverBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return BorderSide(color: _scaleScheme.errorScale.border, width: 2);
|
||||||
|
}
|
||||||
|
return BorderSide(color: _scaleScheme.errorScale.subtleBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return BorderSide(color: _scaleScheme.primaryScale.hoverBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return BorderSide(color: _scaleScheme.primaryScale.border, width: 2);
|
||||||
|
}
|
||||||
|
return BorderSide(color: _scaleScheme.primaryScale.subtleBorder);
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get iconColor => _scaleScheme.primaryScale.primary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get prefixIconColor => MaterialStateColor.resolveWith((states) {
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return _scaleScheme.primaryScale.primary.withAlpha(0x3F);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.error)) {
|
||||||
|
return _scaleScheme.errorScale.primary;
|
||||||
|
}
|
||||||
|
return _scaleScheme.primaryScale.primary;
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Color? get suffixIconColor => MaterialStateColor.resolveWith((states) {
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return _scaleScheme.primaryScale.primary.withAlpha(0x3F);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.error)) {
|
||||||
|
return _scaleScheme.errorScale.primary;
|
||||||
|
}
|
||||||
|
return _scaleScheme.primaryScale.primary;
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextStyle? get labelStyle => MaterialStateTextStyle.resolveWith((states) {
|
||||||
|
final textStyle = _textTheme.bodyLarge ?? const TextStyle();
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.error)) {
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.errorScale.hoverBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.errorScale.hoverBorder);
|
||||||
|
}
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.errorScale.subtleBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.primaryScale.hoverBorder);
|
||||||
|
}
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.primaryScale.hoverBorder);
|
||||||
|
}
|
||||||
|
return textStyle.copyWith(color: _scaleScheme.primaryScale.border);
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextStyle? get floatingLabelStyle => labelStyle;
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextStyle? get helperStyle => MaterialStateTextStyle.resolveWith((states) {
|
||||||
|
final textStyle = _textTheme.bodySmall ?? const TextStyle();
|
||||||
|
if (states.contains(MaterialState.disabled)) {
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.grayScale.border.withAlpha(0x7F));
|
||||||
|
}
|
||||||
|
return textStyle.copyWith(
|
||||||
|
color: _scaleScheme.secondaryScale.border.withAlpha(0x7F));
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((states) {
|
||||||
|
final textStyle = _textTheme.bodySmall ?? const TextStyle();
|
||||||
|
return textStyle.copyWith(color: _scaleScheme.errorScale.primary);
|
||||||
|
});
|
||||||
|
}
|
@ -2,14 +2,17 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'scale_color.dart';
|
import 'scale_color.dart';
|
||||||
|
|
||||||
|
enum ScaleKind { primary, primaryAlpha, secondary, tertiary, gray, error }
|
||||||
|
|
||||||
class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
||||||
ScaleScheme(
|
ScaleScheme({
|
||||||
{required this.primaryScale,
|
required this.primaryScale,
|
||||||
required this.primaryAlphaScale,
|
required this.primaryAlphaScale,
|
||||||
required this.secondaryScale,
|
required this.secondaryScale,
|
||||||
required this.tertiaryScale,
|
required this.tertiaryScale,
|
||||||
required this.grayScale,
|
required this.grayScale,
|
||||||
required this.errorScale});
|
required this.errorScale,
|
||||||
|
});
|
||||||
|
|
||||||
final ScaleColor primaryScale;
|
final ScaleColor primaryScale;
|
||||||
final ScaleColor primaryAlphaScale;
|
final ScaleColor primaryAlphaScale;
|
||||||
@ -18,6 +21,23 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
|||||||
final ScaleColor grayScale;
|
final ScaleColor grayScale;
|
||||||
final ScaleColor errorScale;
|
final ScaleColor errorScale;
|
||||||
|
|
||||||
|
ScaleColor scale(ScaleKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case ScaleKind.primary:
|
||||||
|
return primaryScale;
|
||||||
|
case ScaleKind.primaryAlpha:
|
||||||
|
return primaryAlphaScale;
|
||||||
|
case ScaleKind.secondary:
|
||||||
|
return secondaryScale;
|
||||||
|
case ScaleKind.tertiary:
|
||||||
|
return tertiaryScale;
|
||||||
|
case ScaleKind.gray:
|
||||||
|
return grayScale;
|
||||||
|
case ScaleKind.error:
|
||||||
|
return errorScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ScaleScheme copyWith(
|
ScaleScheme copyWith(
|
||||||
{ScaleColor? primaryScale,
|
{ScaleColor? primaryScale,
|
||||||
@ -50,4 +70,65 @@ class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
|||||||
errorScale: ScaleColor.lerp(errorScale, other.errorScale, t),
|
errorScale: ScaleColor.lerp(errorScale, other.errorScale, t),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColorScheme toColorScheme(Brightness brightness) => ColorScheme(
|
||||||
|
brightness: brightness,
|
||||||
|
primary: primaryScale.primary, // reviewed
|
||||||
|
onPrimary: primaryScale.primaryText, // reviewed
|
||||||
|
// primaryContainer: primaryScale.hoverElementBackground,
|
||||||
|
// onPrimaryContainer: primaryScale.subtleText,
|
||||||
|
secondary: secondaryScale.primary,
|
||||||
|
onSecondary: secondaryScale.primaryText,
|
||||||
|
// secondaryContainer: secondaryScale.hoverElementBackground,
|
||||||
|
// onSecondaryContainer: secondaryScale.subtleText,
|
||||||
|
tertiary: tertiaryScale.primary,
|
||||||
|
onTertiary: tertiaryScale.primaryText,
|
||||||
|
// tertiaryContainer: tertiaryScale.hoverElementBackground,
|
||||||
|
// onTertiaryContainer: tertiaryScale.subtleText,
|
||||||
|
error: errorScale.primary,
|
||||||
|
onError: errorScale.primaryText,
|
||||||
|
// errorContainer: errorScale.hoverElementBackground,
|
||||||
|
// onErrorContainer: errorScale.subtleText,
|
||||||
|
background: grayScale.appBackground, // reviewed
|
||||||
|
onBackground: grayScale.appText, // reviewed
|
||||||
|
surface: primaryScale.primary, // reviewed
|
||||||
|
onSurface: primaryScale.primaryText, // reviewed
|
||||||
|
surfaceVariant: secondaryScale.primary,
|
||||||
|
onSurfaceVariant: secondaryScale.primaryText, // ?? reviewed a little
|
||||||
|
outline: primaryScale.border,
|
||||||
|
outlineVariant: secondaryScale.border,
|
||||||
|
shadow: const Color(0xFF000000),
|
||||||
|
//scrim: primaryScale.background,
|
||||||
|
// inverseSurface: primaryScale.subtleText,
|
||||||
|
// onInverseSurface: primaryScale.subtleBackground,
|
||||||
|
// inversePrimary: primaryScale.hoverBackground,
|
||||||
|
// surfaceTint: primaryAlphaScale.hoverElementBackground,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScaleConfig extends ThemeExtension<ScaleConfig> {
|
||||||
|
ScaleConfig({
|
||||||
|
required this.useVisualIndicators,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool useVisualIndicators;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ScaleConfig copyWith({
|
||||||
|
bool? useVisualIndicators,
|
||||||
|
}) =>
|
||||||
|
ScaleConfig(
|
||||||
|
useVisualIndicators: useVisualIndicators ?? this.useVisualIndicators,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ScaleConfig lerp(ScaleConfig? other, double t) {
|
||||||
|
if (other is! ScaleConfig) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return ScaleConfig(
|
||||||
|
useVisualIndicators:
|
||||||
|
t < .5 ? useVisualIndicators : other.useVisualIndicators,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
151
lib/theme/models/slider_tile.dart
Normal file
151
lib/theme/models/slider_tile.dart
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
|
|
||||||
|
import '../theme.dart';
|
||||||
|
|
||||||
|
class SliderTileAction {
|
||||||
|
const SliderTileAction({
|
||||||
|
required this.actionScale,
|
||||||
|
required this.onPressed,
|
||||||
|
this.key,
|
||||||
|
this.icon,
|
||||||
|
this.label,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Key? key;
|
||||||
|
final ScaleKind actionScale;
|
||||||
|
final String? label;
|
||||||
|
final IconData? icon;
|
||||||
|
final SlidableActionCallback? onPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SliderTile extends StatelessWidget {
|
||||||
|
const SliderTile(
|
||||||
|
{required this.disabled,
|
||||||
|
required this.selected,
|
||||||
|
required this.tileScale,
|
||||||
|
required this.title,
|
||||||
|
this.subtitle = '',
|
||||||
|
this.endActions = const [],
|
||||||
|
this.startActions = const [],
|
||||||
|
this.onTap,
|
||||||
|
this.icon,
|
||||||
|
super.key});
|
||||||
|
|
||||||
|
final bool disabled;
|
||||||
|
final bool selected;
|
||||||
|
final ScaleKind tileScale;
|
||||||
|
final List<SliderTileAction> endActions;
|
||||||
|
final List<SliderTileAction> startActions;
|
||||||
|
final GestureTapCallback? onTap;
|
||||||
|
final IconData? icon;
|
||||||
|
final String title;
|
||||||
|
final String subtitle;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty<bool>('disabled', disabled))
|
||||||
|
..add(DiagnosticsProperty<bool>('selected', selected))
|
||||||
|
..add(DiagnosticsProperty<ScaleKind>('tileScale', tileScale))
|
||||||
|
..add(IterableProperty<SliderTileAction>('endActions', endActions))
|
||||||
|
..add(IterableProperty<SliderTileAction>('startActions', startActions))
|
||||||
|
..add(ObjectFlagProperty<GestureTapCallback?>.has('onTap', onTap))
|
||||||
|
..add(DiagnosticsProperty<IconData?>('icon', icon))
|
||||||
|
..add(StringProperty('title', title))
|
||||||
|
..add(StringProperty('subtitle', subtitle));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// ignore: prefer_expression_function_bodies
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final tileColor = scale.scale(!disabled ? tileScale : ScaleKind.gray);
|
||||||
|
final scalecfg = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
|
final borderColor = selected ? tileColor.hoverBorder : tileColor.border;
|
||||||
|
final backgroundColor = scalecfg.useVisualIndicators && !selected
|
||||||
|
? tileColor.borderText
|
||||||
|
: borderColor;
|
||||||
|
final textColor = scalecfg.useVisualIndicators && !selected
|
||||||
|
? borderColor
|
||||||
|
: tileColor.borderText;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: backgroundColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
side: scalecfg.useVisualIndicators
|
||||||
|
? BorderSide(width: 2, color: borderColor, strokeAlign: 0)
|
||||||
|
: BorderSide.none,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
)),
|
||||||
|
child: Slidable(
|
||||||
|
// Specify a key if the Slidable is dismissible.
|
||||||
|
key: key,
|
||||||
|
endActionPane: endActions.isEmpty
|
||||||
|
? null
|
||||||
|
: ActionPane(
|
||||||
|
motion: const DrawerMotion(),
|
||||||
|
children: endActions
|
||||||
|
.map(
|
||||||
|
(a) => SlidableAction(
|
||||||
|
onPressed: disabled ? null : a.onPressed,
|
||||||
|
backgroundColor: scalecfg.useVisualIndicators
|
||||||
|
? (selected
|
||||||
|
? tileColor.borderText
|
||||||
|
: tileColor.border)
|
||||||
|
: scale.scale(a.actionScale).primary,
|
||||||
|
foregroundColor: scalecfg.useVisualIndicators
|
||||||
|
? (selected
|
||||||
|
? tileColor.border
|
||||||
|
: tileColor.borderText)
|
||||||
|
: scale.scale(a.actionScale).primaryText,
|
||||||
|
icon: a.icon,
|
||||||
|
label: a.label,
|
||||||
|
padding: const EdgeInsets.all(2)),
|
||||||
|
)
|
||||||
|
.toList()),
|
||||||
|
startActionPane: startActions.isEmpty
|
||||||
|
? null
|
||||||
|
: ActionPane(
|
||||||
|
motion: const DrawerMotion(),
|
||||||
|
children: startActions
|
||||||
|
.map(
|
||||||
|
(a) => SlidableAction(
|
||||||
|
onPressed: disabled ? null : a.onPressed,
|
||||||
|
backgroundColor: scalecfg.useVisualIndicators
|
||||||
|
? (selected
|
||||||
|
? tileColor.borderText
|
||||||
|
: tileColor.border)
|
||||||
|
: scale.scale(a.actionScale).primary,
|
||||||
|
foregroundColor: scalecfg.useVisualIndicators
|
||||||
|
? (selected
|
||||||
|
? tileColor.border
|
||||||
|
: tileColor.borderText)
|
||||||
|
: scale.scale(a.actionScale).primaryText,
|
||||||
|
icon: a.icon,
|
||||||
|
label: a.label,
|
||||||
|
padding: const EdgeInsets.all(2)),
|
||||||
|
)
|
||||||
|
.toList()),
|
||||||
|
child: Padding(
|
||||||
|
padding: scalecfg.useVisualIndicators
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: const EdgeInsets.fromLTRB(0, 2, 0, 2),
|
||||||
|
child: ListTile(
|
||||||
|
onTap: onTap,
|
||||||
|
title: Text(
|
||||||
|
title,
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
subtitle: subtitle.isNotEmpty ? Text(subtitle) : null,
|
||||||
|
iconColor: textColor,
|
||||||
|
textColor: textColor,
|
||||||
|
leading: icon == null ? null : Icon(icon)))));
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,8 @@ import 'package:change_case/change_case.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
import '../../tools/tools.dart';
|
import '../views/widget_helpers.dart';
|
||||||
|
import 'contrast_generator.dart';
|
||||||
import 'radix_generator.dart';
|
import 'radix_generator.dart';
|
||||||
|
|
||||||
part 'theme_preference.freezed.dart';
|
part 'theme_preference.freezed.dart';
|
||||||
@ -83,7 +84,7 @@ extension ThemePreferencesExt on ThemePreferences {
|
|||||||
// Special cases
|
// Special cases
|
||||||
case ColorPreference.contrast:
|
case ColorPreference.contrast:
|
||||||
// xxx do contrastGenerator
|
// xxx do contrastGenerator
|
||||||
themeData = radixGenerator(brightness, RadixThemeColor.grim);
|
themeData = contrastGenerator(brightness);
|
||||||
// Generate from Radix
|
// Generate from Radix
|
||||||
case ColorPreference.scarlet:
|
case ColorPreference.scarlet:
|
||||||
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);
|
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);
|
||||||
|
@ -2,7 +2,7 @@ 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 '../theme/theme.dart';
|
import '../theme.dart';
|
||||||
|
|
||||||
class StyledDialog extends StatelessWidget {
|
class StyledDialog extends StatelessWidget {
|
||||||
const StyledDialog({required this.title, required this.child, super.key});
|
const StyledDialog({required this.title, required this.child, super.key});
|
||||||
@ -19,10 +19,11 @@ class StyledDialog extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||||
),
|
),
|
||||||
contentPadding: const EdgeInsets.all(4),
|
contentPadding: const EdgeInsets.all(4),
|
||||||
backgroundColor: scale.primaryScale.border,
|
backgroundColor: scale.primaryScale.dialogBorder,
|
||||||
title: Text(
|
title: Text(
|
||||||
title,
|
title,
|
||||||
style: textTheme.titleMedium,
|
style: textTheme.titleMedium!
|
||||||
|
.copyWith(color: scale.primaryScale.borderText),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
titlePadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
titlePadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
|
@ -1,2 +1,5 @@
|
|||||||
export 'brightness_preferences.dart';
|
export 'brightness_preferences.dart';
|
||||||
export 'color_preferences.dart';
|
export 'color_preferences.dart';
|
||||||
|
export 'scanner_error_widget.dart';
|
||||||
|
export 'styled_dialog.dart';
|
||||||
|
export 'widget_helpers.dart';
|
||||||
|
@ -9,7 +9,7 @@ import 'package:flutter_translate/flutter_translate.dart';
|
|||||||
import 'package:motion_toast/motion_toast.dart';
|
import 'package:motion_toast/motion_toast.dart';
|
||||||
import 'package:quickalert/quickalert.dart';
|
import 'package:quickalert/quickalert.dart';
|
||||||
|
|
||||||
import '../theme/theme.dart';
|
import '../theme.dart';
|
||||||
|
|
||||||
extension BorderExt on Widget {
|
extension BorderExt on Widget {
|
||||||
DecoratedBox debugBorder() => DecoratedBox(
|
DecoratedBox debugBorder() => DecoratedBox(
|
||||||
@ -35,19 +35,22 @@ Widget buildProgressIndicator() => Builder(builder: (context) {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
return SpinKitFoldingCube(
|
return SpinKitFoldingCube(
|
||||||
color: scale.tertiaryScale.background,
|
color: scale.tertiaryScale.primary,
|
||||||
size: 80,
|
size: 80,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget waitingPage({String? text}) => Builder(
|
Widget waitingPage({String? text}) => Builder(builder: (context) {
|
||||||
builder: (context) => ColoredBox(
|
final theme = Theme.of(context);
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
child: Center(
|
return ColoredBox(
|
||||||
child: Column(children: [
|
color: scale.tertiaryScale.primaryText,
|
||||||
buildProgressIndicator().expanded(),
|
child: Center(
|
||||||
if (text != null) Text(text)
|
child: Column(children: [
|
||||||
]))));
|
buildProgressIndicator().expanded(),
|
||||||
|
if (text != null) Text(text)
|
||||||
|
])));
|
||||||
|
});
|
||||||
|
|
||||||
Widget debugPage(String text) => Builder(
|
Widget debugPage(String text) => Builder(
|
||||||
builder: (context) => ColoredBox(
|
builder: (context) => ColoredBox(
|
||||||
@ -132,12 +135,30 @@ void showInfoToast(BuildContext context, String message) {
|
|||||||
).show(context);
|
).show(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget insetBorder(
|
||||||
|
// {required BuildContext context,
|
||||||
|
// required bool enabled,
|
||||||
|
// required Color color,
|
||||||
|
// required Widget child}) {
|
||||||
|
// if (!enabled) {
|
||||||
|
// return child;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return Stack({
|
||||||
|
// children: [] {
|
||||||
|
// DecoratedBox(decoration: BoxDecoration()
|
||||||
|
// child,
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
Widget styledTitleContainer({
|
Widget styledTitleContainer({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required String title,
|
required String title,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
Color? borderColor,
|
Color? borderColor,
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
|
Color? titleColor,
|
||||||
}) {
|
}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
@ -153,7 +174,7 @@ Widget styledTitleContainer({
|
|||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: textTheme.titleMedium!
|
style: textTheme.titleMedium!
|
||||||
.copyWith(color: scale.primaryScale.subtleText),
|
.copyWith(color: titleColor ?? scale.primaryScale.borderText),
|
||||||
).paddingLTRB(8, 8, 8, 4),
|
).paddingLTRB(8, 8, 8, 4),
|
||||||
DecoratedBox(
|
DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
@ -174,6 +195,7 @@ Widget styledBottomSheet({
|
|||||||
required Widget child,
|
required Widget child,
|
||||||
Color? borderColor,
|
Color? borderColor,
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
|
Color? titleColor,
|
||||||
}) {
|
}) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
@ -181,7 +203,7 @@ Widget styledBottomSheet({
|
|||||||
|
|
||||||
return DecoratedBox(
|
return DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: borderColor ?? scale.primaryScale.border,
|
color: borderColor ?? scale.primaryScale.dialogBorder,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16),
|
topLeft: Radius.circular(16),
|
||||||
@ -190,7 +212,7 @@ Widget styledBottomSheet({
|
|||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: textTheme.titleMedium!
|
style: textTheme.titleMedium!
|
||||||
.copyWith(color: scale.primaryScale.subtleText),
|
.copyWith(color: titleColor ?? scale.primaryScale.borderText),
|
||||||
).paddingLTRB(8, 8, 8, 4),
|
).paddingLTRB(8, 8, 8, 4),
|
||||||
DecoratedBox(
|
DecoratedBox(
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
@ -52,27 +52,23 @@ class _EnterPasswordDialogState extends State<EnterPasswordDialog> {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
|
||||||
return Dialog(
|
return StyledDialog(
|
||||||
backgroundColor: scale.grayScale.subtleBackground,
|
title: widget.matchPass == null
|
||||||
|
? translate('enter_password_dialog.enter_password')
|
||||||
|
: translate('enter_password_dialog.reenter_password'),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: formKey,
|
key: formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
|
||||||
widget.matchPass == null
|
|
||||||
? translate('enter_password_dialog.enter_password')
|
|
||||||
: translate('enter_password_dialog.reenter_password'),
|
|
||||||
style: theme.textTheme.titleLarge,
|
|
||||||
).paddingAll(16),
|
|
||||||
TextField(
|
TextField(
|
||||||
controller: passwordController,
|
controller: passwordController,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
enableSuggestions: false,
|
enableSuggestions: false,
|
||||||
obscureText:
|
obscureText: !_passwordVisible,
|
||||||
!_passwordVisible, //This will obscure text dynamically
|
obscuringCharacter: '*',
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
FilteringTextInputFormatter.singleLineFormatter
|
FilteringTextInputFormatter.singleLineFormatter
|
||||||
],
|
],
|
||||||
@ -87,7 +83,7 @@ class _EnterPasswordDialogState extends State<EnterPasswordDialog> {
|
|||||||
? null
|
? null
|
||||||
: Icon(Icons.check_circle,
|
: Icon(Icons.check_circle,
|
||||||
color: passwordController.text == widget.matchPass
|
color: passwordController.text == widget.matchPass
|
||||||
? scale.primaryScale.background
|
? scale.primaryScale.primary
|
||||||
: scale.grayScale.subtleBackground),
|
: scale.grayScale.subtleBackground),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
|
@ -67,20 +67,16 @@ class _EnterPinDialogState extends State<EnterPinDialog> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Optionally you can use form to validate the Pinput
|
/// Optionally you can use form to validate the Pinput
|
||||||
return Dialog(
|
return StyledDialog(
|
||||||
backgroundColor: scale.grayScale.subtleBackground,
|
title: !widget.reenter
|
||||||
|
? translate('enter_pin_dialog.enter_pin')
|
||||||
|
: translate('enter_pin_dialog.reenter_pin'),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: formKey,
|
key: formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
|
||||||
!widget.reenter
|
|
||||||
? translate('enter_pin_dialog.enter_pin')
|
|
||||||
: translate('enter_pin_dialog.reenter_pin'),
|
|
||||||
style: theme.textTheme.titleLarge,
|
|
||||||
).paddingAll(16),
|
|
||||||
Directionality(
|
Directionality(
|
||||||
// Specify direction if desired
|
// Specify direction if desired
|
||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
|
@ -5,10 +5,7 @@ export 'loggy.dart';
|
|||||||
export 'phono_byte.dart';
|
export 'phono_byte.dart';
|
||||||
export 'pop_control.dart';
|
export 'pop_control.dart';
|
||||||
export 'responsive.dart';
|
export 'responsive.dart';
|
||||||
export 'scanner_error_widget.dart';
|
|
||||||
export 'shared_preferences.dart';
|
export 'shared_preferences.dart';
|
||||||
export 'state_logger.dart';
|
export 'state_logger.dart';
|
||||||
export 'stream_listenable.dart';
|
export 'stream_listenable.dart';
|
||||||
export 'styled_dialog.dart';
|
|
||||||
export 'widget_helpers.dart';
|
|
||||||
export 'window_control.dart';
|
export 'window_control.dart';
|
||||||
|
@ -140,17 +140,18 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: scale.primaryScale.primary,
|
||||||
appBar: DefaultAppBar(
|
appBar: DefaultAppBar(
|
||||||
title: Text(translate('developer.title')),
|
title: Text(translate('developer.title')),
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: scale.primaryScale.appText),
|
icon: Icon(Icons.arrow_back, color: scale.primaryScale.primaryText),
|
||||||
onPressed: () => GoRouterHelper(context).pop(),
|
onPressed: () => GoRouterHelper(context).pop(),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.copy),
|
icon: const Icon(Icons.copy),
|
||||||
color: scale.primaryScale.appText,
|
color: scale.primaryScale.primaryText,
|
||||||
disabledColor: scale.grayScale.subtleText,
|
disabledColor: scale.primaryScale.primaryText.withAlpha(0x3F),
|
||||||
onPressed: _terminalController.selection == null
|
onPressed: _terminalController.selection == null
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
@ -158,17 +159,22 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
}),
|
}),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.clear_all),
|
icon: const Icon(Icons.clear_all),
|
||||||
color: scale.primaryScale.appText,
|
color: scale.primaryScale.primaryText,
|
||||||
disabledColor: scale.grayScale.subtleText,
|
disabledColor: scale.primaryScale.primaryText.withAlpha(0x3F),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await QuickAlert.show(
|
await QuickAlert.show(
|
||||||
context: context,
|
context: context,
|
||||||
type: QuickAlertType.confirm,
|
type: QuickAlertType.confirm,
|
||||||
title: translate('developer.are_you_sure_clear'),
|
title: translate('developer.are_you_sure_clear'),
|
||||||
textColor: scale.primaryScale.appText,
|
titleColor: scale.primaryScale.appText,
|
||||||
confirmBtnColor: scale.primaryScale.elementBackground,
|
textColor: scale.primaryScale.subtleText,
|
||||||
backgroundColor: scale.primaryScale.subtleBackground,
|
confirmBtnColor: scale.primaryScale.primary,
|
||||||
headerBackgroundColor: scale.primaryScale.background,
|
cancelBtnTextStyle: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 18,
|
||||||
|
color: scale.primaryScale.appText),
|
||||||
|
backgroundColor: scale.primaryScale.appBackground,
|
||||||
|
headerBackgroundColor: scale.primaryScale.primary,
|
||||||
confirmBtnText: translate('button.ok'),
|
confirmBtnText: translate('button.ok'),
|
||||||
cancelBtnText: translate('button.cancel'),
|
cancelBtnText: translate('button.cancel'),
|
||||||
onConfirmBtnTap: () async {
|
onConfirmBtnTap: () async {
|
||||||
@ -194,13 +200,23 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
width: 64,
|
width: 64,
|
||||||
height: 40,
|
height: 40,
|
||||||
render: ResultRender.icon,
|
render: ResultRender.icon,
|
||||||
|
icon: SizedBox(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: DropdownArrowPainter(
|
||||||
|
color: scale.primaryScale.primaryText))),
|
||||||
textStyle: textTheme.labelMedium!
|
textStyle: textTheme.labelMedium!
|
||||||
.copyWith(color: scale.primaryScale.appText),
|
.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.activeElementBackground),
|
color: scale.primaryScale.border,
|
||||||
boxDecoration:
|
borderRadius: BorderRadius.circular(8),
|
||||||
BoxDecoration(color: scale.primaryScale.elementBackground),
|
),
|
||||||
|
boxDecoration: BoxDecoration(
|
||||||
|
color: scale.primaryScale.hoverBorder,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
dropdownOptions: DropdownOptions(
|
dropdownOptions: DropdownOptions(
|
||||||
width: 160,
|
width: 160,
|
||||||
@ -224,7 +240,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||||
selectedPadding: const EdgeInsets.fromLTRB(8, 4, 8, 4)),
|
selectedPadding: const EdgeInsets.fromLTRB(8, 4, 8, 4)),
|
||||||
dropdownList: _logLevelDropdownItems,
|
dropdownList: _logLevelDropdownItems,
|
||||||
)
|
).paddingLTRB(0, 0, 8, 0)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
@ -245,13 +261,19 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
||||||
border: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(color: scale.primaryScale.border)),
|
borderSide: BorderSide.none),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
fillColor: scale.primaryScale.subtleBackground,
|
fillColor: scale.primaryScale.subtleBackground,
|
||||||
hintText: translate('developer.command'),
|
hintText: translate('developer.command'),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: const Icon(Icons.send),
|
icon: Icon(Icons.send,
|
||||||
|
color: _debugCommandController.text.isEmpty
|
||||||
|
? scale.primaryScale.primary.withAlpha(0x3F)
|
||||||
|
: scale.primaryScale.primary),
|
||||||
onPressed: _debugCommandController.text.isEmpty
|
onPressed: _debugCommandController.text.isEmpty
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
|
@ -33,32 +33,32 @@ class SignalStrengthMeterWidget extends StatelessWidget {
|
|||||||
switch (connectionState.attachment.state) {
|
switch (connectionState.attachment.state) {
|
||||||
case AttachmentState.detached:
|
case AttachmentState.detached:
|
||||||
iconWidget = Icon(Icons.signal_cellular_nodata,
|
iconWidget = Icon(Icons.signal_cellular_nodata,
|
||||||
size: iconSize, color: scale.grayScale.appText);
|
size: iconSize, color: scale.primaryScale.primaryText);
|
||||||
return;
|
return;
|
||||||
case AttachmentState.detaching:
|
case AttachmentState.detaching:
|
||||||
iconWidget = Icon(Icons.signal_cellular_off,
|
iconWidget = Icon(Icons.signal_cellular_off,
|
||||||
size: iconSize, color: scale.grayScale.appText);
|
size: iconSize, color: scale.primaryScale.primaryText);
|
||||||
return;
|
return;
|
||||||
case AttachmentState.attaching:
|
case AttachmentState.attaching:
|
||||||
value = 0;
|
value = 0;
|
||||||
color = scale.primaryScale.appText;
|
color = scale.primaryScale.primaryText;
|
||||||
case AttachmentState.attachedWeak:
|
case AttachmentState.attachedWeak:
|
||||||
value = 1;
|
value = 1;
|
||||||
color = scale.primaryScale.appText;
|
color = scale.primaryScale.primaryText;
|
||||||
case AttachmentState.attachedStrong:
|
case AttachmentState.attachedStrong:
|
||||||
value = 2;
|
value = 2;
|
||||||
color = scale.primaryScale.appText;
|
color = scale.primaryScale.primaryText;
|
||||||
case AttachmentState.attachedGood:
|
case AttachmentState.attachedGood:
|
||||||
value = 3;
|
value = 3;
|
||||||
color = scale.primaryScale.appText;
|
color = scale.primaryScale.primaryText;
|
||||||
case AttachmentState.fullyAttached:
|
case AttachmentState.fullyAttached:
|
||||||
value = 4;
|
value = 4;
|
||||||
color = scale.primaryScale.appText;
|
color = scale.primaryScale.primaryText;
|
||||||
case AttachmentState.overAttached:
|
case AttachmentState.overAttached:
|
||||||
value = 4;
|
value = 4;
|
||||||
color = scale.secondaryScale.subtleText;
|
color = scale.primaryScale.primaryText;
|
||||||
}
|
}
|
||||||
inactiveColor = scale.grayScale.subtleText;
|
inactiveColor = scale.primaryScale.primaryText;
|
||||||
|
|
||||||
iconWidget = SignalStrengthIndicator.bars(
|
iconWidget = SignalStrengthIndicator.bars(
|
||||||
value: value,
|
value: value,
|
||||||
@ -66,7 +66,7 @@ class SignalStrengthMeterWidget extends StatelessWidget {
|
|||||||
inactiveColor: inactiveColor,
|
inactiveColor: inactiveColor,
|
||||||
size: iconSize,
|
size: iconSize,
|
||||||
barCount: 4,
|
barCount: 4,
|
||||||
spacing: 1);
|
spacing: 2);
|
||||||
},
|
},
|
||||||
loading: () => {iconWidget = const Icon(Icons.warning)},
|
loading: () => {iconWidget = const Icon(Icons.warning)},
|
||||||
error: (e, st) => {
|
error: (e, st) => {
|
||||||
|
@ -69,7 +69,7 @@ class DHTShortArrayCubit<T> extends Cubit<DHTShortArrayBusyState<T>>
|
|||||||
// Because this is async, we could get an update while we're
|
// Because this is async, we could get an update while we're
|
||||||
// still processing the last one. Only called after init future has run
|
// still processing the last one. Only called after init future has run
|
||||||
// so we dont have to wait for that here.
|
// so we dont have to wait for that here.
|
||||||
_sspUpdate.busyUpdate<T, AsyncValue<IList<T>>>(
|
_sspUpdate.busyUpdate<T, DHTShortArrayState<T>>(
|
||||||
busy, (emit) async => _refreshInner(emit));
|
busy, (emit) async => _refreshInner(emit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +470,8 @@ class _DHTShortArrayHead {
|
|||||||
_subscription = null;
|
_subscription = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called when the shortarray changes online and we find out from a watch
|
||||||
|
// but not when we make a change locally
|
||||||
Future<void> _onHeadValueChanged(
|
Future<void> _onHeadValueChanged(
|
||||||
DHTRecord record, Uint8List? data, List<ValueSubkeyRange> subkeys) async {
|
DHTRecord record, Uint8List? data, List<ValueSubkeyRange> subkeys) async {
|
||||||
// If head record subkey zero changes, then the layout
|
// If head record subkey zero changes, then the layout
|
||||||
|
Loading…
Reference in New Issue
Block a user