mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-01-11 07:39:32 -05:00
ui cleanup
This commit is contained in:
parent
1f99279cd2
commit
23ec185324
@ -58,12 +58,15 @@
|
||||
"account_page": {
|
||||
"contact_invitations": "Contact Invitations"
|
||||
},
|
||||
"accounts_menu": {
|
||||
"invite_contact": "Invite Contact",
|
||||
"add_contact_sheet": {
|
||||
"new_contact": "New Contact",
|
||||
"create_invite": "Create Invitation",
|
||||
"scan_invite": "Scan Invitation",
|
||||
"paste_invite": "Paste Invitation"
|
||||
},
|
||||
"add_chat_sheet": {
|
||||
"new_chat": "New Chat"
|
||||
},
|
||||
"create_invitation_dialog": {
|
||||
"title": "Create Contact Invitation",
|
||||
"connect_with_me": "Connect with me on VeilidChat!",
|
||||
|
@ -113,7 +113,9 @@ class NewAccountPageState extends State<NewAccountPage> {
|
||||
body: _newAccountForm(
|
||||
context,
|
||||
onSubmit: (formKey) async {
|
||||
// dismiss the keyboard by unfocusing the textfield
|
||||
FocusScope.of(context).unfocus();
|
||||
|
||||
try {
|
||||
final name =
|
||||
_formKey.currentState!.fields[formFieldName]!.value as String;
|
||||
|
62
lib/app.dart
62
lib/app.dart
@ -1,6 +1,7 @@
|
||||
import 'package:animated_theme_switcher/animated_theme_switcher.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
@ -12,9 +13,15 @@ import 'init.dart';
|
||||
import 'layout/splash.dart';
|
||||
import 'router/router.dart';
|
||||
import 'settings/settings.dart';
|
||||
import 'theme/models/theme_preference.dart';
|
||||
import 'tick.dart';
|
||||
import 'tools/loggy.dart';
|
||||
import 'veilid_processor/veilid_processor.dart';
|
||||
|
||||
class ReloadThemeIntent extends Intent {
|
||||
const ReloadThemeIntent();
|
||||
}
|
||||
|
||||
class VeilidChatApp extends StatelessWidget {
|
||||
const VeilidChatApp({
|
||||
required this.initialThemeData,
|
||||
@ -25,6 +32,28 @@ class VeilidChatApp extends StatelessWidget {
|
||||
|
||||
final ThemeData initialThemeData;
|
||||
|
||||
void _reloadTheme(BuildContext context) {
|
||||
log.info('Reloading theme');
|
||||
final theme =
|
||||
PreferencesRepository.instance.value.themePreferences.themeData();
|
||||
ThemeSwitcher.of(context).changeTheme(theme: theme);
|
||||
}
|
||||
|
||||
Widget _buildShortcuts(
|
||||
{required BuildContext context,
|
||||
required Widget Function(BuildContext) builder}) =>
|
||||
ThemeSwitcher(
|
||||
builder: (context) => Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(
|
||||
LogicalKeyboardKey.alt, LogicalKeyboardKey.keyR):
|
||||
const ReloadThemeIntent(),
|
||||
},
|
||||
child: Actions(actions: <Type, Action<Intent>>{
|
||||
ReloadThemeIntent: CallbackAction<ReloadThemeIntent>(
|
||||
onInvoke: (intent) => _reloadTheme(context)),
|
||||
}, child: Focus(autofocus: true, child: builder(context)))));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => FutureProvider<VeilidChatGlobalInit?>(
|
||||
initialData: null,
|
||||
@ -68,21 +97,24 @@ class VeilidChatApp extends StatelessWidget {
|
||||
)
|
||||
],
|
||||
child: BackgroundTicker(
|
||||
builder: (context) => MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
routerConfig: context.watch<RouterCubit>().router(),
|
||||
title: translate('app.title'),
|
||||
theme: theme,
|
||||
localizationsDelegates: [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
FormBuilderLocalizations.delegate,
|
||||
localizationDelegate
|
||||
],
|
||||
supportedLocales:
|
||||
localizationDelegate.supportedLocales,
|
||||
locale: localizationDelegate.currentLocale,
|
||||
)),
|
||||
child: _buildShortcuts(
|
||||
context: context,
|
||||
builder: (context) => MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
routerConfig:
|
||||
context.watch<RouterCubit>().router(),
|
||||
title: translate('app.title'),
|
||||
theme: theme,
|
||||
localizationsDelegates: [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
FormBuilderLocalizations.delegate,
|
||||
localizationDelegate
|
||||
],
|
||||
supportedLocales:
|
||||
localizationDelegate.supportedLocales,
|
||||
locale: localizationDelegate.currentLocale,
|
||||
))),
|
||||
)),
|
||||
);
|
||||
});
|
||||
|
71
lib/chat/views/new_chat_bottom_sheet.dart
Normal file
71
lib/chat/views/new_chat_bottom_sheet.dart
Normal file
@ -0,0 +1,71 @@
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
|
||||
Widget newChatBottomSheetBuilder(
|
||||
BuildContext sheetContext, BuildContext context) {
|
||||
final theme = Theme.of(sheetContext);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
return KeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
onKeyEvent: (ke) {
|
||||
if (ke.logicalKey == LogicalKeyboardKey.escape) {
|
||||
Navigator.pop(sheetContext);
|
||||
}
|
||||
},
|
||||
child: styledBottomSheet(
|
||||
context: context,
|
||||
title: translate('add_chat_sheet.new_chat'),
|
||||
child: SizedBox(
|
||||
height: 160,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Text(
|
||||
'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))));
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
export 'chat_component.dart';
|
||||
export 'empty_chat_widget.dart';
|
||||
export 'new_chat_bottom_sheet.dart';
|
||||
export 'no_conversation_widget.dart';
|
||||
|
@ -7,7 +7,6 @@ import 'package:searchable_listview/searchable_listview.dart';
|
||||
|
||||
import '../../contacts/contacts.dart';
|
||||
import '../../proto/proto.dart' as proto;
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import '../chat_list.dart';
|
||||
|
||||
@ -17,10 +16,6 @@ class ChatSingleContactListWidget extends StatelessWidget {
|
||||
@override
|
||||
// ignore: prefer_expression_function_bodies
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
//final textTheme = theme.textTheme;
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
final contactListV = context.watch<ContactListCubit>().state;
|
||||
|
||||
return contactListV.builder((context, contactList) {
|
||||
@ -29,55 +24,49 @@ class ChatSingleContactListWidget extends StatelessWidget {
|
||||
valueMapper: (c) => c);
|
||||
|
||||
final chatListV = context.watch<ChatListCubit>().state;
|
||||
return chatListV.builder((context, chatList) => SizedBox.expand(
|
||||
return chatListV
|
||||
.builder((context, chatList) => SizedBox.expand(
|
||||
child: styledTitleContainer(
|
||||
context: context,
|
||||
title: translate('chat_list.chats'),
|
||||
child: SizedBox.expand(
|
||||
child: (chatList.isEmpty)
|
||||
? const EmptyChatListWidget()
|
||||
: SearchableList<proto.Chat>(
|
||||
initialList: chatList.toList(),
|
||||
builder: (l, i, c) {
|
||||
child: (chatList.isEmpty)
|
||||
? const EmptyChatListWidget()
|
||||
: SearchableList<proto.Chat>(
|
||||
initialList: chatList.toList(),
|
||||
builder: (l, i, c) {
|
||||
final contact =
|
||||
contactMap[c.remoteConversationRecordKey];
|
||||
if (contact == null) {
|
||||
return const Text('...');
|
||||
}
|
||||
return ChatSingleContactItemWidget(
|
||||
contact: contact,
|
||||
disabled: contactListV.busy);
|
||||
},
|
||||
filter: (value) {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return chatList.where((c) {
|
||||
final contact =
|
||||
contactMap[c.remoteConversationRecordKey];
|
||||
if (contact == null) {
|
||||
return const Text('...');
|
||||
return false;
|
||||
}
|
||||
return ChatSingleContactItemWidget(
|
||||
contact: contact,
|
||||
disabled: contactListV.busy);
|
||||
},
|
||||
filter: (value) {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return chatList.where((c) {
|
||||
final contact =
|
||||
contactMap[c.remoteConversationRecordKey];
|
||||
if (contact == null) {
|
||||
return false;
|
||||
}
|
||||
return contact.editedProfile.name
|
||||
.toLowerCase()
|
||||
.contains(lowerValue) ||
|
||||
contact.editedProfile.pronouns
|
||||
.toLowerCase()
|
||||
.contains(lowerValue);
|
||||
}).toList();
|
||||
},
|
||||
spaceBetweenSearchAndList: 4,
|
||||
inputDecoration: InputDecoration(
|
||||
labelText: translate('chat_list.search'),
|
||||
contentPadding: const EdgeInsets.all(2),
|
||||
fillColor: scale.primaryScale.elementBackground,
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: scale.primaryScale.hoverBorder,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
).paddingAll(8))))
|
||||
.paddingLTRB(8, 0, 8, 8));
|
||||
return contact.editedProfile.name
|
||||
.toLowerCase()
|
||||
.contains(lowerValue) ||
|
||||
contact.editedProfile.pronouns
|
||||
.toLowerCase()
|
||||
.contains(lowerValue);
|
||||
}).toList();
|
||||
},
|
||||
spaceBetweenSearchAndList: 4,
|
||||
inputDecoration: InputDecoration(
|
||||
labelText: translate('chat_list.search'),
|
||||
),
|
||||
),
|
||||
).paddingAll(8))))
|
||||
.paddingLTRB(8, 0, 8, 8);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ class CreateInvitationDialogState extends State<CreateInvitationDialog> {
|
||||
LengthLimitingTextInputFormatter(128),
|
||||
],
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
//border: const OutlineInputBorder(),
|
||||
hintText:
|
||||
translate('create_invitation_dialog.enter_message_hint'),
|
||||
labelText: translate('create_invitation_dialog.message')),
|
||||
|
72
lib/contact_invitation/views/new_contact_bottom_sheet.dart
Normal file
72
lib/contact_invitation/views/new_contact_bottom_sheet.dart
Normal file
@ -0,0 +1,72 @@
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import 'create_invitation_dialog.dart';
|
||||
import 'paste_invitation_dialog.dart';
|
||||
import 'scan_invitation_dialog.dart';
|
||||
|
||||
Widget newContactBottomSheetBuilder(
|
||||
BuildContext sheetContext, BuildContext context) {
|
||||
final theme = Theme.of(sheetContext);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
return KeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
onKeyEvent: (ke) {
|
||||
if (ke.logicalKey == LogicalKeyboardKey.escape) {
|
||||
Navigator.pop(sheetContext);
|
||||
}
|
||||
},
|
||||
child: styledBottomSheet(
|
||||
context: context,
|
||||
title: translate('add_contact_sheet.new_contact'),
|
||||
child: SizedBox(
|
||||
height: 160,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
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('add_contact_sheet.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('add_contact_sheet.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('add_contact_sheet.paste_invite'),
|
||||
)
|
||||
])
|
||||
]).paddingAll(16))));
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
|
||||
import '../../theme/theme.dart';
|
||||
import 'paste_invitation_dialog.dart';
|
||||
import 'scan_invitation_dialog.dart';
|
||||
import 'create_invitation_dialog.dart';
|
||||
|
||||
Widget newContactInvitationBottomSheetBuilder(
|
||||
BuildContext sheetContext, BuildContext context) {
|
||||
final theme = Theme.of(sheetContext);
|
||||
final textTheme = theme.textTheme;
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
return KeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
onKeyEvent: (ke) {
|
||||
if (ke.logicalKey == LogicalKeyboardKey.escape) {
|
||||
Navigator.pop(sheetContext);
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 200,
|
||||
child: Column(children: [
|
||||
Text(translate('accounts_menu.invite_contact'),
|
||||
style: textTheme.titleMedium)
|
||||
.paddingAll(8),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
|
||||
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'))
|
||||
])
|
||||
]).expanded()
|
||||
])));
|
||||
}
|
@ -125,7 +125,6 @@ class PasteInvitationDialogState extends State<PasteInvitationDialog> {
|
||||
maxLines: null,
|
||||
controller: _pasteTextController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
hintText: '--- BEGIN VEILIDCHAT CONTACT INVITE ----\n'
|
||||
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n'
|
||||
'---- END VEILIDCHAT CONTACT INVITE -----\n',
|
||||
|
@ -3,6 +3,6 @@ export 'contact_invitation_item_widget.dart';
|
||||
export 'contact_invitation_list_widget.dart';
|
||||
export 'create_invitation_dialog.dart';
|
||||
export 'invitation_dialog.dart';
|
||||
export 'new_contact_invitation_bottom_sheet.dart';
|
||||
export 'new_contact_bottom_sheet.dart';
|
||||
export 'paste_invitation_dialog.dart';
|
||||
export 'scan_invitation_dialog.dart';
|
||||
|
@ -29,14 +29,15 @@ class ContactItemWidget extends StatelessWidget {
|
||||
final remoteConversationKey =
|
||||
contact.remoteConversationRecordKey.toVeilid();
|
||||
|
||||
const selected =
|
||||
false; // xxx: eventually when we have selectable contacts: activeContactCubit.state == remoteConversationRecordKey;
|
||||
const selected = false; // xxx: eventually when we have selectable contacts:
|
||||
// activeContactCubit.state == remoteConversationRecordKey;
|
||||
|
||||
return Container(
|
||||
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(
|
||||
@ -102,9 +103,11 @@ class ContactItemWidget extends StatelessWidget {
|
||||
? 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,
|
||||
|
@ -6,7 +6,6 @@ import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:searchable_listview/searchable_listview.dart';
|
||||
|
||||
import '../../proto/proto.dart' as proto;
|
||||
import '../../theme/theme.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import 'contact_item_widget.dart';
|
||||
import 'empty_contact_list_widget.dart';
|
||||
@ -26,47 +25,33 @@ class ContactListWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
//final textTheme = theme.textTheme;
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
return SizedBox.expand(
|
||||
child: styledTitleContainer(
|
||||
context: context,
|
||||
title: translate('contact_list.title'),
|
||||
child: SizedBox.expand(
|
||||
child: (contactList.isEmpty)
|
||||
? const EmptyContactListWidget()
|
||||
: SearchableList<proto.Contact>(
|
||||
initialList: contactList.toList(),
|
||||
builder: (l, i, c) =>
|
||||
ContactItemWidget(contact: c, disabled: disabled),
|
||||
filter: (value) {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return contactList
|
||||
.where((element) =>
|
||||
element.editedProfile.name
|
||||
.toLowerCase()
|
||||
.contains(lowerValue) ||
|
||||
element.editedProfile.pronouns
|
||||
.toLowerCase()
|
||||
.contains(lowerValue))
|
||||
.toList();
|
||||
},
|
||||
spaceBetweenSearchAndList: 4,
|
||||
inputDecoration: InputDecoration(
|
||||
labelText: translate('contact_list.search'),
|
||||
contentPadding: const EdgeInsets.all(2),
|
||||
fillColor: scale.primaryScale.appText,
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: scale.primaryScale.hoverBorder,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
).paddingAll(8),
|
||||
))).paddingLTRB(8, 0, 8, 8);
|
||||
}
|
||||
Widget build(BuildContext context) => SizedBox.expand(
|
||||
child: styledTitleContainer(
|
||||
context: context,
|
||||
title: translate('contact_list.title'),
|
||||
child: SizedBox.expand(
|
||||
child: (contactList.isEmpty)
|
||||
? const EmptyContactListWidget()
|
||||
: SearchableList<proto.Contact>(
|
||||
initialList: contactList.toList(),
|
||||
builder: (l, i, c) =>
|
||||
ContactItemWidget(contact: c, disabled: disabled),
|
||||
filter: (value) {
|
||||
final lowerValue = value.toLowerCase();
|
||||
return contactList
|
||||
.where((element) =>
|
||||
element.editedProfile.name
|
||||
.toLowerCase()
|
||||
.contains(lowerValue) ||
|
||||
element.editedProfile.pronouns
|
||||
.toLowerCase()
|
||||
.contains(lowerValue))
|
||||
.toList();
|
||||
},
|
||||
spaceBetweenSearchAndList: 4,
|
||||
inputDecoration: InputDecoration(
|
||||
labelText: translate('contact_list.search'),
|
||||
),
|
||||
).paddingAll(8),
|
||||
))).paddingLTRB(8, 0, 8, 8);
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ class HomeAccountReadyChat extends StatefulWidget {
|
||||
}
|
||||
|
||||
class HomeAccountReadyChatState extends State<HomeAccountReadyChat> {
|
||||
final _unfocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -26,7 +24,6 @@ class HomeAccountReadyChatState extends State<HomeAccountReadyChat> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_unfocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -42,8 +39,6 @@ class HomeAccountReadyChatState extends State<HomeAccountReadyChat> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SafeArea(
|
||||
child: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(_unfocusNode),
|
||||
child: buildChatComponent(context),
|
||||
));
|
||||
);
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ class AccountPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class AccountPageState extends State<AccountPage> {
|
||||
final _unfocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -27,7 +25,6 @@ class AccountPageState extends State<AccountPage> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_unfocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,6 @@ class ChatsPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class ChatsPageState extends State<ChatsPage> {
|
||||
final _unfocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -20,7 +18,6 @@ class ChatsPageState extends State<ChatsPage> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_unfocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,9 @@ import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:preload_page_view/preload_page_view.dart';
|
||||
import 'package:stylish_bottom_bar/model/bar_items.dart';
|
||||
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
||||
|
||||
import '../../../../chat/chat.dart';
|
||||
import '../../../../contact_invitation/contact_invitation.dart';
|
||||
import '../../../../theme/theme.dart';
|
||||
import '../../../../tools/tools.dart';
|
||||
@ -28,8 +28,6 @@ class MainPager extends StatefulWidget {
|
||||
class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
final _unfocusNode = FocusNode();
|
||||
|
||||
var _currentPage = 0;
|
||||
final pageController = PreloadPageController();
|
||||
|
||||
@ -56,7 +54,6 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_unfocusNode.dispose();
|
||||
pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@ -127,21 +124,13 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
||||
});
|
||||
}
|
||||
|
||||
Widget _onNewChatBottomSheetBuilder(
|
||||
BuildContext sheetContext, BuildContext context) =>
|
||||
const SizedBox(
|
||||
height: 200,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Group and custom chat functionality is not available yet')));
|
||||
|
||||
Widget _bottomSheetBuilder(BuildContext sheetContext, BuildContext context) {
|
||||
if (_currentPage == 0) {
|
||||
// New contact invitation
|
||||
return newContactInvitationBottomSheetBuilder(sheetContext, context);
|
||||
return newContactBottomSheetBuilder(sheetContext, context);
|
||||
} else if (_currentPage == 1) {
|
||||
// New chat
|
||||
return _onNewChatBottomSheetBuilder(sheetContext, context);
|
||||
return newChatBottomSheetBuilder(sheetContext, context);
|
||||
} else {
|
||||
// Unknown error
|
||||
return debugPage('unknown page');
|
||||
|
@ -19,8 +19,6 @@ class HomeShell extends StatefulWidget {
|
||||
}
|
||||
|
||||
class HomeShellState extends State<HomeShell> {
|
||||
final _unfocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -28,7 +26,6 @@ class HomeShellState extends State<HomeShell> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_unfocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -69,11 +66,9 @@ class HomeShellState extends State<HomeShell> {
|
||||
|
||||
// XXX: eventually write account switcher here
|
||||
return SafeArea(
|
||||
child: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(_unfocusNode),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: scale.primaryScale.activeElementBackground),
|
||||
child: buildWithLogin(context))));
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: scale.primaryScale.activeElementBackground),
|
||||
child: buildWithLogin(context)));
|
||||
}
|
||||
}
|
||||
|
@ -53,11 +53,11 @@ class SettingsPageState extends State<SettingsPage> {
|
||||
child: ListView(
|
||||
children: [
|
||||
buildSettingsPageColorPreferences(
|
||||
onChanged: () => setState(() {})),
|
||||
context: context, onChanged: () => setState(() {})),
|
||||
buildSettingsPageBrightnessPreferences(
|
||||
onChanged: () => setState(() {})),
|
||||
],
|
||||
context: context, onChanged: () => setState(() {})),
|
||||
].map((x) => x.paddingLTRB(0, 0, 0, 8)).toList(),
|
||||
),
|
||||
).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||
).paddingSymmetric(horizontal: 24, vertical: 16),
|
||||
)));
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
|
||||
import 'package:radix_colors/radix_colors.dart';
|
||||
|
||||
import '../../tools/tools.dart';
|
||||
import 'scale_color.dart';
|
||||
import 'scale_scheme.dart';
|
||||
|
||||
@ -571,26 +574,27 @@ ColorScheme _scaleToColorScheme(Brightness brightness, ScaleScheme scale) =>
|
||||
Colors.red, // scale.primaryScale.hoverElementBackground,
|
||||
onPrimaryContainer: Colors.green, //scale.primaryScale.subtleText,
|
||||
secondary: scale.secondaryScale.background,
|
||||
onSecondary: scale.secondaryScale.appText,
|
||||
onSecondary: scale.secondaryScale.foregroundText,
|
||||
secondaryContainer: scale.secondaryScale.hoverElementBackground,
|
||||
onSecondaryContainer: scale.secondaryScale.subtleText,
|
||||
tertiary: scale.tertiaryScale.background,
|
||||
onTertiary: scale.tertiaryScale.appText,
|
||||
onTertiary: scale.tertiaryScale.foregroundText,
|
||||
tertiaryContainer: scale.tertiaryScale.hoverElementBackground,
|
||||
onTertiaryContainer: scale.tertiaryScale.subtleText,
|
||||
error: scale.errorScale.background,
|
||||
onError: scale.errorScale.appText,
|
||||
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.activeElementBackground, // reviewed
|
||||
onSurface: scale.primaryScale.subtleText, // reviewed
|
||||
surface: scale.primaryScale.background, // reviewed
|
||||
onSurface: scale.primaryScale.foregroundText, // reviewed
|
||||
surfaceVariant: scale.primaryScale.elementBackground,
|
||||
onSurfaceVariant: scale.primaryScale.subtleText, // ?? reviewed a little
|
||||
onSurfaceVariant:
|
||||
scale.primaryScale.foregroundText, // ?? reviewed a little
|
||||
outline: scale.primaryScale.border,
|
||||
outlineVariant: scale.primaryScale.subtleBorder,
|
||||
shadow: RadixColors.dark.gray.step1,
|
||||
shadow: const Color(0xFF000000),
|
||||
scrim: scale.primaryScale.background,
|
||||
inverseSurface: scale.primaryScale.subtleText,
|
||||
onInverseSurface: scale.primaryScale.subtleBackground,
|
||||
@ -612,7 +616,7 @@ ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) =>
|
||||
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
||||
border: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8))),
|
||||
),
|
||||
inputContainerDecoration:
|
||||
BoxDecoration(color: scale.primaryScale.border),
|
||||
@ -641,10 +645,39 @@ ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) =>
|
||||
fontSize: 64,
|
||||
));
|
||||
|
||||
TextTheme _makeTextTheme(Brightness brightness) {
|
||||
late final TextTheme textTheme;
|
||||
if (Platform.isIOS) {
|
||||
textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackCupertino
|
||||
: Typography.whiteCupertino;
|
||||
} else if (Platform.isMacOS) {
|
||||
textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackRedwoodCity
|
||||
: Typography.whiteRedwoodCity;
|
||||
} else if (Platform.isAndroid || Platform.isFuchsia) {
|
||||
textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackMountainView
|
||||
: Typography.whiteMountainView;
|
||||
} else if (Platform.isLinux) {
|
||||
textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackHelsinki
|
||||
: Typography.whiteHelsinki;
|
||||
} else if (Platform.isWindows) {
|
||||
textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackRedmond
|
||||
: Typography.whiteRedmond;
|
||||
} else {
|
||||
log.warning('unknown platform');
|
||||
textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackHelsinki
|
||||
: Typography.whiteHelsinki;
|
||||
}
|
||||
return textTheme;
|
||||
}
|
||||
|
||||
ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
||||
final textTheme = (brightness == Brightness.light)
|
||||
? Typography.blackCupertino
|
||||
: Typography.whiteCupertino;
|
||||
final textTheme = _makeTextTheme(brightness);
|
||||
final radix = _radixScheme(brightness, themeColor);
|
||||
final scaleScheme = radix.toScale();
|
||||
final colorScheme = _scaleToColorScheme(brightness, scaleScheme);
|
||||
@ -655,8 +688,42 @@ ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
|
||||
bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
|
||||
elevation: 0,
|
||||
modalElevation: 0,
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))),
|
||||
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.background,
|
||||
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))),
|
||||
),
|
||||
focusColor: scaleScheme.primaryScale.activeElementBackground,
|
||||
hoverColor: scaleScheme.primaryScale.hoverElementBackground,
|
||||
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,
|
||||
]);
|
||||
|
@ -22,7 +22,7 @@ List<DropdownMenuItem<dynamic>> _getBrightnessDropdownItems() {
|
||||
}
|
||||
|
||||
Widget buildSettingsPageBrightnessPreferences(
|
||||
{required void Function() onChanged}) {
|
||||
{required BuildContext context, required void Function() onChanged}) {
|
||||
final preferencesRepository = PreferencesRepository.instance;
|
||||
final themePreferences = preferencesRepository.value.themePreferences;
|
||||
return ThemeSwitcher.withTheme(
|
||||
|
@ -30,7 +30,8 @@ List<DropdownMenuItem<dynamic>> _getThemeDropdownItems() {
|
||||
.toList();
|
||||
}
|
||||
|
||||
Widget buildSettingsPageColorPreferences({required void Function() onChanged}) {
|
||||
Widget buildSettingsPageColorPreferences(
|
||||
{required BuildContext context, required void Function() onChanged}) {
|
||||
final preferencesRepository = PreferencesRepository.instance;
|
||||
final themePreferences = preferencesRepository.value.themePreferences;
|
||||
return ThemeSwitcher.withTheme(
|
||||
|
@ -1,24 +1,17 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:veilid_support/veilid_support.dart';
|
||||
|
||||
import 'veilid_processor/veilid_processor.dart';
|
||||
|
||||
class BackgroundTicker extends StatefulWidget {
|
||||
const BackgroundTicker({required this.builder, super.key});
|
||||
const BackgroundTicker({required this.child, super.key});
|
||||
|
||||
final Widget Function(BuildContext) builder;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
BackgroundTickerState createState() => BackgroundTickerState();
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ObjectFlagProperty<Widget Function(BuildContext p1)>.has(
|
||||
'builder', builder));
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundTickerState extends State<BackgroundTicker> {
|
||||
@ -48,7 +41,7 @@ class BackgroundTickerState extends State<BackgroundTicker> {
|
||||
@override
|
||||
// ignore: prefer_expression_function_bodies
|
||||
Widget build(BuildContext context) {
|
||||
return widget.builder(context);
|
||||
return widget.child;
|
||||
}
|
||||
|
||||
Future<void> _onTick() async {
|
||||
|
@ -154,7 +154,7 @@ Widget styledTitleContainer({
|
||||
title,
|
||||
style: textTheme.titleMedium!
|
||||
.copyWith(color: scale.primaryScale.subtleText),
|
||||
).paddingLTRB(8, 8, 8, 8),
|
||||
).paddingLTRB(8, 8, 8, 4),
|
||||
DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
color:
|
||||
@ -168,6 +168,43 @@ Widget styledTitleContainer({
|
||||
]));
|
||||
}
|
||||
|
||||
Widget styledBottomSheet({
|
||||
required BuildContext context,
|
||||
required String title,
|
||||
required Widget child,
|
||||
Color? borderColor,
|
||||
Color? backgroundColor,
|
||||
}) {
|
||||
final theme = Theme.of(context);
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
final textTheme = theme.textTheme;
|
||||
|
||||
return DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
color: borderColor ?? scale.primaryScale.border,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16)))),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
Text(
|
||||
title,
|
||||
style: textTheme.titleMedium!
|
||||
.copyWith(color: scale.primaryScale.subtleText),
|
||||
).paddingLTRB(8, 8, 8, 4),
|
||||
DecoratedBox(
|
||||
decoration: ShapeDecoration(
|
||||
color:
|
||||
backgroundColor ?? scale.primaryScale.subtleBackground,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16)))),
|
||||
child: child)
|
||||
.paddingLTRB(4, 4, 4, 0)
|
||||
]));
|
||||
}
|
||||
|
||||
bool get isPlatformDark =>
|
||||
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
||||
Brightness.dark;
|
||||
|
@ -80,6 +80,18 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugCommand.startsWith('change_log_ignore ')) {
|
||||
final args = debugCommand.split(' ');
|
||||
if (args.length < 3) {
|
||||
_debugOut('Incorrect number of arguments');
|
||||
return;
|
||||
}
|
||||
final layer = args[1];
|
||||
final changes = args[2].split(',');
|
||||
Veilid.instance.changeLogIgnore(layer, changes);
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugCommand == 'ellet') {
|
||||
setState(() {
|
||||
_showEllet = !_showEllet;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:veilid/veilid.dart';
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:veilid/veilid.dart';
|
||||
|
||||
Map<String, dynamic> getDefaultVeilidPlatformConfig(
|
||||
bool isWeb, String appName) {
|
||||
final ignoreLogTargetsStr =
|
||||
|
Loading…
Reference in New Issue
Block a user