mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-10-01 06:55:46 -04:00
sliver refactor
This commit is contained in:
parent
67812b3c6f
commit
2fa3cbd21c
@ -97,8 +97,9 @@
|
|||||||
"invalid_account_title": "Invalid Account",
|
"invalid_account_title": "Invalid Account",
|
||||||
"invalid_account_text": "Account is invalid, removing from list"
|
"invalid_account_text": "Account is invalid, removing from list"
|
||||||
},
|
},
|
||||||
"account_page": {
|
"contacts_page": {
|
||||||
"contact_invitations": "Contact Invitations"
|
"contacts": "Contacts",
|
||||||
|
"invitations": "Invitations"
|
||||||
},
|
},
|
||||||
"add_contact_sheet": {
|
"add_contact_sheet": {
|
||||||
"new_contact": "New Contact",
|
"new_contact": "New Contact",
|
||||||
@ -176,14 +177,13 @@
|
|||||||
"password_does_not_match": "Password does not match"
|
"password_does_not_match": "Password does not match"
|
||||||
},
|
},
|
||||||
"contact_list": {
|
"contact_list": {
|
||||||
"title": "Contacts",
|
|
||||||
"invite_people": "Invite people to VeilidChat",
|
"invite_people": "Invite people to VeilidChat",
|
||||||
"search": "Search contacts",
|
"search": "Search contacts",
|
||||||
"invitation": "Invitation"
|
"invitation": "Invitation"
|
||||||
},
|
},
|
||||||
"chat_list": {
|
"chat_list": {
|
||||||
"search": "Search chats",
|
"search": "Search chats",
|
||||||
"start_a_conversation": "Start a conversation",
|
"start_a_conversation": "Start A Conversation",
|
||||||
"chats": "Chats",
|
"chats": "Chats",
|
||||||
"groups": "Groups"
|
"groups": "Groups"
|
||||||
},
|
},
|
||||||
|
@ -58,6 +58,8 @@ PODS:
|
|||||||
- nanopb/encode (= 2.30910.0)
|
- nanopb/encode (= 2.30910.0)
|
||||||
- nanopb/decode (2.30910.0)
|
- nanopb/decode (2.30910.0)
|
||||||
- nanopb/encode (2.30910.0)
|
- nanopb/encode (2.30910.0)
|
||||||
|
- native_device_orientation (0.0.1):
|
||||||
|
- Flutter
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
- pasteboard (0.0.1):
|
- pasteboard (0.0.1):
|
||||||
@ -91,6 +93,7 @@ DEPENDENCIES:
|
|||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
|
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
|
||||||
|
- native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
@ -129,6 +132,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||||
mobile_scanner:
|
mobile_scanner:
|
||||||
:path: ".symlinks/plugins/mobile_scanner/ios"
|
:path: ".symlinks/plugins/mobile_scanner/ios"
|
||||||
|
native_device_orientation:
|
||||||
|
:path: ".symlinks/plugins/native_device_orientation/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
pasteboard:
|
pasteboard:
|
||||||
@ -169,6 +174,7 @@ SPEC CHECKSUMS:
|
|||||||
MLKitVision: e858c5f125ecc288e4a31127928301eaba9ae0c1
|
MLKitVision: e858c5f125ecc288e4a31127928301eaba9ae0c1
|
||||||
mobile_scanner: 8564358885a9253c43f822435b70f9345c87224f
|
mobile_scanner: 8564358885a9253c43f822435b70f9345c87224f
|
||||||
nanopb: 438bc412db1928dac798aa6fd75726007be04262
|
nanopb: 438bc412db1928dac798aa6fd75726007be04262
|
||||||
|
native_device_orientation: 348b10c346a60ebbc62fb235a4fdb5d1b61a8f55
|
||||||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||||
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
|
pasteboard: 982969ebaa7c78af3e6cc7761e8f5e77565d9ce0
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
|
@ -44,25 +44,11 @@ class EditAccountPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EditAccountPageState extends State<EditAccountPage> {
|
class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
|
||||||
bool _isInAsyncCall = false;
|
_EditAccountPageState()
|
||||||
|
: super(
|
||||||
@override
|
titleBarStyle: TitleBarStyle.normal,
|
||||||
void initState() {
|
orientationCapability: OrientationCapability.portraitOnly);
|
||||||
super.initState();
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.normal, OrientationCapability.portraitOnly);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
unawaited(
|
|
||||||
changeWindowSetup(TitleBarStyle.normal, OrientationCapability.normal));
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _editAccountForm(BuildContext context,
|
Widget _editAccountForm(BuildContext context,
|
||||||
{required Future<void> Function(GlobalKey<FormBuilderState>)
|
{required Future<void> Function(GlobalKey<FormBuilderState>)
|
||||||
@ -314,4 +300,8 @@ class _EditAccountPageState extends State<EditAccountPage> {
|
|||||||
]).paddingSymmetric(horizontal: 24, vertical: 8)))
|
]).paddingSymmetric(horizontal: 24, vertical: 8)))
|
||||||
.withModalHUD(context, displayModalHUD);
|
.withModalHUD(context, displayModalHUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool _isInAsyncCall = false;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.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';
|
||||||
@ -20,18 +22,11 @@ class NewAccountPage extends StatefulWidget {
|
|||||||
State createState() => _NewAccountPageState();
|
State createState() => _NewAccountPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NewAccountPageState extends State<NewAccountPage> {
|
class _NewAccountPageState extends WindowSetupState<NewAccountPage> {
|
||||||
bool _isInAsyncCall = false;
|
_NewAccountPageState()
|
||||||
|
: super(
|
||||||
@override
|
titleBarStyle: TitleBarStyle.normal,
|
||||||
void initState() {
|
orientationCapability: OrientationCapability.portraitOnly);
|
||||||
super.initState();
|
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.normal, OrientationCapability.portraitOnly);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _newAccountForm(BuildContext context,
|
Widget _newAccountForm(BuildContext context,
|
||||||
{required Future<void> Function(GlobalKey<FormBuilderState>) onSubmit}) {
|
{required Future<void> Function(GlobalKey<FormBuilderState>) onSubmit}) {
|
||||||
@ -120,4 +115,8 @@ class _NewAccountPageState extends State<NewAccountPage> {
|
|||||||
)).paddingSymmetric(horizontal: 24, vertical: 8),
|
)).paddingSymmetric(horizontal: 24, vertical: 8),
|
||||||
).withModalHUD(context, displayModalHUD);
|
).withModalHUD(context, displayModalHUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool _isInAsyncCall = false;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class ProfileWidget extends StatelessWidget {
|
|||||||
: scale.primaryScale.borderText,
|
: scale.primaryScale.borderText,
|
||||||
width: 2),
|
width: 2),
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(16 * scaleConfig.borderRadiusScale))),
|
Radius.circular(12 * scaleConfig.borderRadiusScale))),
|
||||||
),
|
),
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
@ -29,22 +30,17 @@ class ShowRecoveryKeyPage extends StatefulWidget {
|
|||||||
_name = name;
|
_name = name;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ShowRecoveryKeyPageState createState() => ShowRecoveryKeyPageState();
|
State<ShowRecoveryKeyPage> createState() => _ShowRecoveryKeyPageState();
|
||||||
|
|
||||||
final WritableSuperIdentity _writableSuperIdentity;
|
final WritableSuperIdentity _writableSuperIdentity;
|
||||||
final String _name;
|
final String _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShowRecoveryKeyPageState extends State<ShowRecoveryKeyPage> {
|
class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
|
||||||
@override
|
_ShowRecoveryKeyPageState()
|
||||||
void initState() {
|
: super(
|
||||||
super.initState();
|
titleBarStyle: TitleBarStyle.normal,
|
||||||
|
orientationCapability: OrientationCapability.portraitOnly);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.normal, OrientationCapability.portraitOnly);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _shareRecoveryKey(
|
Future<void> _shareRecoveryKey(
|
||||||
BuildContext context, Uint8List recoveryKey, String name) async {
|
BuildContext context, Uint8List recoveryKey, String name) async {
|
||||||
|
@ -15,7 +15,6 @@ import 'init.dart';
|
|||||||
import 'layout/splash.dart';
|
import 'layout/splash.dart';
|
||||||
import 'router/router.dart';
|
import 'router/router.dart';
|
||||||
import 'settings/settings.dart';
|
import 'settings/settings.dart';
|
||||||
import 'theme/models/theme_preference.dart';
|
|
||||||
import 'theme/theme.dart';
|
import 'theme/theme.dart';
|
||||||
import 'tick.dart';
|
import 'tick.dart';
|
||||||
import 'tools/loggy.dart';
|
import 'tools/loggy.dart';
|
||||||
@ -92,7 +91,7 @@ class VeilidChatApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) => FutureProvider<VeilidChatGlobalInit?>(
|
Widget build(BuildContext context) => FutureProvider<VeilidChatGlobalInit?>(
|
||||||
initialData: null,
|
initialData: null,
|
||||||
create: (context) async => VeilidChatGlobalInit.initialize(),
|
create: (context) async => VeilidChatGlobalInit.initialize(),
|
||||||
builder: (context, child) {
|
builder: (context, __) {
|
||||||
final globalInit = context.watch<VeilidChatGlobalInit?>();
|
final globalInit = context.watch<VeilidChatGlobalInit?>();
|
||||||
if (globalInit == null) {
|
if (globalInit == null) {
|
||||||
// Splash screen until we're done with init
|
// Splash screen until we're done with init
|
||||||
|
@ -60,36 +60,33 @@ class ChatListWidget extends StatelessWidget {
|
|||||||
final chatListV = context.watch<ChatListCubit>().state;
|
final chatListV = context.watch<ChatListCubit>().state;
|
||||||
return chatListV
|
return chatListV
|
||||||
.builder((context, chatList) => SizedBox.expand(
|
.builder((context, chatList) => SizedBox.expand(
|
||||||
child: styledTitleContainer(
|
child: styledTitleContainer(
|
||||||
context: context,
|
context: context,
|
||||||
title: translate('chat_list.chats'),
|
title: translate('chat_list.chats'),
|
||||||
child: SizedBox.expand(
|
child: (chatList.isEmpty)
|
||||||
child: (chatList.isEmpty)
|
? const SizedBox.expand(child: EmptyChatListWidget())
|
||||||
? const EmptyChatListWidget()
|
: SearchableList<proto.Chat>(
|
||||||
: SearchableList<proto.Chat>(
|
initialList: chatList.map((x) => x.value).toList(),
|
||||||
initialList: chatList.map((x) => x.value).toList(),
|
itemBuilder: (c) {
|
||||||
itemBuilder: (c) {
|
switch (c.whichKind()) {
|
||||||
switch (c.whichKind()) {
|
case proto.Chat_Kind.direct:
|
||||||
case proto.Chat_Kind.direct:
|
return _itemBuilderDirect(c.direct, contactMap,
|
||||||
return _itemBuilderDirect(
|
contactListV.busy || chatListV.busy);
|
||||||
c.direct,
|
case proto.Chat_Kind.group:
|
||||||
contactMap,
|
return const Text(
|
||||||
contactListV.busy || chatListV.busy);
|
'group chats not yet supported!');
|
||||||
case proto.Chat_Kind.group:
|
case proto.Chat_Kind.notSet:
|
||||||
return const Text(
|
throw StateError('unknown chat kind');
|
||||||
'group chats not yet supported!');
|
}
|
||||||
case proto.Chat_Kind.notSet:
|
},
|
||||||
throw StateError('unknown chat kind');
|
filter: (value) =>
|
||||||
}
|
_itemFilter(contactMap, chatList, value),
|
||||||
},
|
spaceBetweenSearchAndList: 4,
|
||||||
filter: (value) =>
|
inputDecoration: InputDecoration(
|
||||||
_itemFilter(contactMap, chatList, value),
|
labelText: translate('chat_list.search'),
|
||||||
spaceBetweenSearchAndList: 4,
|
),
|
||||||
inputDecoration: InputDecoration(
|
).paddingAll(8),
|
||||||
labelText: translate('chat_list.search'),
|
)))
|
||||||
),
|
|
||||||
),
|
|
||||||
).paddingAll(8))))
|
|
||||||
.paddingLTRB(8, 0, 8, 8);
|
.paddingLTRB(8, 0, 8, 8);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import 'package:awesome_extensions/awesome_extensions.dart';
|
|||||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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';
|
||||||
@ -31,58 +32,58 @@ class ContactInvitationListWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ContactInvitationListWidgetState
|
class ContactInvitationListWidgetState
|
||||||
extends State<ContactInvitationListWidget> {
|
extends State<ContactInvitationListWidget>
|
||||||
final ScrollController _scrollController = ScrollController();
|
with SingleTickerProviderStateMixin {
|
||||||
|
late final _controller = AnimationController(
|
||||||
|
vsync: this, duration: const Duration(milliseconds: 250), value: 1);
|
||||||
|
late final _animation =
|
||||||
|
CurvedAnimation(parent: _controller, curve: Curves.easeInOut);
|
||||||
|
bool _expanded = true;
|
||||||
|
|
||||||
@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 theme = Theme.of(context);
|
||||||
//final textTheme = theme.textTheme;
|
// final textTheme = theme.textTheme;
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
return Container(
|
return styledExpandingSliver(
|
||||||
width: double.infinity,
|
context: context,
|
||||||
margin: const EdgeInsets.fromLTRB(4, 0, 4, 4),
|
animation: _animation,
|
||||||
decoration: ShapeDecoration(
|
expanded: _expanded,
|
||||||
shape: RoundedRectangleBorder(
|
backgroundColor: scaleConfig.preferBorders
|
||||||
borderRadius: BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
? scale.primaryScale.subtleBackground
|
||||||
)),
|
: scale.primaryScale.subtleBorder,
|
||||||
constraints: const BoxConstraints(maxHeight: 100),
|
onTap: () {
|
||||||
child: Container(
|
setState(() {
|
||||||
width: double.infinity,
|
_expanded = !_expanded;
|
||||||
decoration: ShapeDecoration(
|
});
|
||||||
color: scale.primaryScale.subtleBackground,
|
_controller.animateTo(_expanded ? 1 : 0);
|
||||||
shape: RoundedRectangleBorder(
|
},
|
||||||
borderRadius:
|
title: translate('contacts_page.invitations'),
|
||||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
sliver: SliverList.builder(
|
||||||
)),
|
itemCount: widget.contactInvitationRecordList.length,
|
||||||
child: ListView.builder(
|
itemBuilder: (context, index) {
|
||||||
shrinkWrap: true,
|
if (index < 0 ||
|
||||||
controller: _scrollController,
|
index >= widget.contactInvitationRecordList.length) {
|
||||||
itemCount: widget.contactInvitationRecordList.length,
|
return null;
|
||||||
itemBuilder: (context, index) {
|
}
|
||||||
if (index < 0 ||
|
return ContactInvitationItemWidget(
|
||||||
index >= widget.contactInvitationRecordList.length) {
|
contactInvitationRecord:
|
||||||
return null;
|
widget.contactInvitationRecordList[index],
|
||||||
}
|
disabled: widget.disabled,
|
||||||
return ContactInvitationItemWidget(
|
key: ObjectKey(widget.contactInvitationRecordList[index]))
|
||||||
contactInvitationRecord:
|
.paddingLTRB(4, 2, 4, 2);
|
||||||
widget.contactInvitationRecordList[index],
|
},
|
||||||
disabled: widget.disabled,
|
findChildIndexCallback: (key) {
|
||||||
key: ObjectKey(widget.contactInvitationRecordList[index]))
|
final index = widget.contactInvitationRecordList.indexOf(
|
||||||
.paddingLTRB(4, 2, 4, 2);
|
(key as ObjectKey).value! as proto.ContactInvitationRecord);
|
||||||
},
|
if (index == -1) {
|
||||||
findChildIndexCallback: (key) {
|
return null;
|
||||||
final index = widget.contactInvitationRecordList.indexOf(
|
}
|
||||||
(key as ObjectKey).value! as proto.ContactInvitationRecord);
|
return index;
|
||||||
if (index == -1) {
|
},
|
||||||
return null;
|
));
|
||||||
}
|
|
||||||
return index;
|
|
||||||
},
|
|
||||||
).paddingLTRB(4, 6, 4, 6)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,49 +28,50 @@ class ContactListWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ContactListWidgetState extends State<ContactListWidget> {
|
class _ContactListWidgetState extends State<ContactListWidget>
|
||||||
@override
|
with SingleTickerProviderStateMixin {
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
//final textTheme = theme.textTheme;
|
||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
return styledTitleContainer(
|
return SliverLayoutBuilder(
|
||||||
context: context,
|
builder: (context, constraints) => styledHeaderSliver(
|
||||||
title: translate('contact_list.title'),
|
context: context,
|
||||||
child: SearchableList<proto.Contact>(
|
backgroundColor: scaleConfig.preferBorders
|
||||||
shrinkWrap: true,
|
? scale.primaryScale.subtleBackground
|
||||||
initialList: widget.contactList.toList(),
|
: scale.primaryScale.subtleBorder,
|
||||||
itemBuilder: (c) =>
|
title: translate('contacts_page.contacts'),
|
||||||
ContactItemWidget(contact: c, disabled: widget.disabled)
|
sliver: SliverFillRemaining(
|
||||||
.paddingLTRB(0, 4, 0, 0),
|
child: SearchableList<proto.Contact>.sliver(
|
||||||
filter: (value) {
|
initialList: widget.contactList.toList(),
|
||||||
final lowerValue = value.toLowerCase();
|
itemBuilder: (c) =>
|
||||||
return widget.contactList
|
ContactItemWidget(contact: c, disabled: widget.disabled)
|
||||||
.where((element) =>
|
.paddingLTRB(0, 4, 0, 0),
|
||||||
element.nickname.toLowerCase().contains(lowerValue) ||
|
filter: (value) {
|
||||||
element.profile.name.toLowerCase().contains(lowerValue) ||
|
final lowerValue = value.toLowerCase();
|
||||||
element.profile.pronouns.toLowerCase().contains(lowerValue))
|
return widget.contactList
|
||||||
.toList();
|
.where((element) =>
|
||||||
},
|
element.nickname.toLowerCase().contains(lowerValue) ||
|
||||||
searchFieldHeight: 40,
|
element.profile.name
|
||||||
spaceBetweenSearchAndList: 4,
|
.toLowerCase()
|
||||||
emptyWidget: const EmptyContactListWidget(),
|
.contains(lowerValue) ||
|
||||||
defaultSuffixIconColor: scale.primaryScale.border,
|
element.profile.pronouns
|
||||||
closeKeyboardWhenScrolling: true,
|
.toLowerCase()
|
||||||
inputDecoration: InputDecoration(
|
.contains(lowerValue))
|
||||||
labelText: translate('contact_list.search'),
|
.toList();
|
||||||
),
|
},
|
||||||
).paddingAll(8),
|
searchFieldHeight: 40,
|
||||||
).paddingLTRB(8, 0, 8, 8);
|
spaceBetweenSearchAndList: 4,
|
||||||
|
emptyWidget: const EmptyContactListWidget(),
|
||||||
|
defaultSuffixIconColor: scale.primaryScale.border,
|
||||||
|
closeKeyboardWhenScrolling: true,
|
||||||
|
inputDecoration: InputDecoration(
|
||||||
|
labelText: translate('contact_list.search'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
(scaleConfig.preferBorders || scaleConfig.useVisualIndicators)
|
(scaleConfig.preferBorders || scaleConfig.useVisualIndicators)
|
||||||
? activeBorder
|
? activeBorder
|
||||||
: null,
|
: null,
|
||||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
borderRadius: 12 * scaleConfig.borderRadiusScale,
|
||||||
callback: callback,
|
callback: callback,
|
||||||
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
footerButtonIcon: loggedIn ? Icons.edit_outlined : null,
|
||||||
footerCallback: footerCallback,
|
footerCallback: footerCallback,
|
||||||
@ -197,11 +197,11 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
loading: () => _wrapInBox(
|
loading: () => _wrapInBox(
|
||||||
child: buildProgressIndicator(),
|
child: buildProgressIndicator(),
|
||||||
color: scaleScheme.grayScale.subtleBorder,
|
color: scaleScheme.grayScale.subtleBorder,
|
||||||
borderRadius: 16 * scaleConfig.borderRadiusScale),
|
borderRadius: 12 * scaleConfig.borderRadiusScale),
|
||||||
error: (err, st) => _wrapInBox(
|
error: (err, st) => _wrapInBox(
|
||||||
child: errorPage(err, st),
|
child: errorPage(err, st),
|
||||||
color: scaleScheme.errorScale.subtleBorder,
|
color: scaleScheme.errorScale.subtleBorder,
|
||||||
borderRadius: 16 * scaleConfig.borderRadiusScale),
|
borderRadius: 12 * scaleConfig.borderRadiusScale),
|
||||||
);
|
);
|
||||||
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
|
loggedInAccounts.add(loggedInAccount.paddingLTRB(0, 0, 0, 8));
|
||||||
} else {
|
} else {
|
||||||
@ -254,7 +254,7 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
return IconButton(
|
return IconButton(
|
||||||
icon: icon,
|
icon: icon,
|
||||||
color: border,
|
color: border,
|
||||||
constraints: const BoxConstraints.expand(height: 64, width: 64),
|
constraints: const BoxConstraints.expand(height: 48, width: 48),
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||||
if (states.contains(WidgetState.hovered)) {
|
if (states.contains(WidgetState.hovered)) {
|
||||||
@ -269,18 +269,18 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
return RoundedRectangleBorder(
|
return RoundedRectangleBorder(
|
||||||
side: BorderSide(color: hoverBorder, width: 2),
|
side: BorderSide(color: hoverBorder, width: 2),
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
Radius.circular(12 * scaleConfig.borderRadiusScale)));
|
||||||
}
|
}
|
||||||
if (states.contains(WidgetState.focused)) {
|
if (states.contains(WidgetState.focused)) {
|
||||||
return RoundedRectangleBorder(
|
return RoundedRectangleBorder(
|
||||||
side: BorderSide(color: activeBorder, width: 2),
|
side: BorderSide(color: activeBorder, width: 2),
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
Radius.circular(12 * scaleConfig.borderRadiusScale)));
|
||||||
}
|
}
|
||||||
return RoundedRectangleBorder(
|
return RoundedRectangleBorder(
|
||||||
side: BorderSide(color: border, width: 2),
|
side: BorderSide(color: border, width: 2),
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(16 * scaleConfig.borderRadiusScale)));
|
Radius.circular(12 * scaleConfig.borderRadiusScale)));
|
||||||
})),
|
})),
|
||||||
tooltip: tooltip,
|
tooltip: tooltip,
|
||||||
onPressed: onPressed);
|
onPressed: onPressed);
|
||||||
@ -413,12 +413,18 @@ class _DrawerMenuState extends State<DrawerMenu> {
|
|||||||
_getBottomButtons(),
|
_getBottomButtons(),
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Text('${translate('menu.version')} $packageInfoVersion',
|
Text('${translate('menu.version')} $packageInfoVersion',
|
||||||
style: theme.textTheme.labelMedium!
|
style: theme.textTheme.labelMedium!.copyWith(
|
||||||
.copyWith(color: scale.tertiaryScale.hoverBorder)),
|
color: scaleConfig.preferBorders
|
||||||
|
? scale.tertiaryScale.hoverBorder
|
||||||
|
: scale.tertiaryScale.subtleBackground)),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
SignalStrengthMeterWidget(
|
SignalStrengthMeterWidget(
|
||||||
color: scale.tertiaryScale.hoverBorder,
|
color: scaleConfig.preferBorders
|
||||||
inactiveColor: scale.tertiaryScale.border,
|
? scale.tertiaryScale.hoverBorder
|
||||||
|
: scale.tertiaryScale.subtleBackground,
|
||||||
|
inactiveColor: scaleConfig.preferBorders
|
||||||
|
? scale.tertiaryScale.border
|
||||||
|
: scale.tertiaryScale.elementBackground,
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
]).paddingAll(16),
|
]).paddingAll(16),
|
||||||
|
@ -8,7 +8,6 @@ import 'package:veilid_support/veilid_support.dart';
|
|||||||
|
|
||||||
import '../../account_manager/account_manager.dart';
|
import '../../account_manager/account_manager.dart';
|
||||||
import '../../theme/theme.dart';
|
import '../../theme/theme.dart';
|
||||||
import '../../tools/tools.dart';
|
|
||||||
import 'drawer_menu/drawer_menu.dart';
|
import 'drawer_menu/drawer_menu.dart';
|
||||||
import 'home_account_invalid.dart';
|
import 'home_account_invalid.dart';
|
||||||
import 'home_account_locked.dart';
|
import 'home_account_locked.dart';
|
||||||
@ -37,9 +36,6 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
|
.indexWhere((x) => x.superIdentity.recordKey == activeLocalAccount);
|
||||||
final canClose = activeIndex != -1;
|
final canClose = activeIndex != -1;
|
||||||
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.normal, OrientationCapability.normal);
|
|
||||||
|
|
||||||
if (!canClose) {
|
if (!canClose) {
|
||||||
await _zoomDrawerController.open!();
|
await _zoomDrawerController.open!();
|
||||||
}
|
}
|
||||||
@ -129,7 +125,6 @@ class HomeScreenState extends State<HomeScreen>
|
|||||||
final canClose = activeIndex != -1;
|
final canClose = activeIndex != -1;
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
style: theme.textTheme.bodySmall!,
|
style: theme.textTheme.bodySmall!,
|
||||||
child: ZoomDrawer(
|
child: ZoomDrawer(
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
|
||||||
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_translate/flutter_translate.dart';
|
|
||||||
|
|
||||||
import '../../../contact_invitation/contact_invitation.dart';
|
|
||||||
import '../../../contacts/contacts.dart';
|
|
||||||
import '../../../theme/theme.dart';
|
|
||||||
|
|
||||||
class AccountPage extends StatefulWidget {
|
|
||||||
const AccountPage({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
AccountPageState createState() => AccountPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class AccountPageState extends State<AccountPage> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 scaleConfig = theme.extension<ScaleConfig>()!;
|
|
||||||
|
|
||||||
final cilState = context.watch<ContactInvitationListCubit>().state;
|
|
||||||
final cilBusy = cilState.busy;
|
|
||||||
final contactInvitationRecordList =
|
|
||||||
cilState.state.asData?.value.map((x) => x.value).toIList() ??
|
|
||||||
const IListConst([]);
|
|
||||||
|
|
||||||
final ciState = context.watch<ContactListCubit>().state;
|
|
||||||
final ciBusy = ciState.busy;
|
|
||||||
final contactList =
|
|
||||||
ciState.state.asData?.value.map((x) => x.value).toIList() ??
|
|
||||||
const IListConst([]);
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
child: Column(children: <Widget>[
|
|
||||||
if (contactInvitationRecordList.isNotEmpty)
|
|
||||||
ExpansionTile(
|
|
||||||
tilePadding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
|
||||||
backgroundColor: scale.primaryScale.border,
|
|
||||||
collapsedBackgroundColor: scale.primaryScale.border,
|
|
||||||
dense: true,
|
|
||||||
minTileHeight: 16,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
|
||||||
),
|
|
||||||
collapsedShape: RoundedRectangleBorder(
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
translate('account_page.contact_invitations'),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: textTheme.titleSmall!
|
|
||||||
.copyWith(color: scale.primaryScale.borderText),
|
|
||||||
),
|
|
||||||
iconColor: scale.primaryScale.borderText,
|
|
||||||
collapsedIconColor: scale.primaryScale.borderText,
|
|
||||||
initiallyExpanded: true,
|
|
||||||
children: [
|
|
||||||
ContactInvitationListWidget(
|
|
||||||
contactInvitationRecordList: contactInvitationRecordList,
|
|
||||||
disabled: cilBusy)
|
|
||||||
],
|
|
||||||
).paddingLTRB(8, 0, 8, 8),
|
|
||||||
ContactListWidget(contactList: contactList, disabled: ciBusy).expanded(),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../chat_list/chat_list.dart';
|
import '../../../chat_list/chat_list.dart';
|
||||||
@ -24,8 +23,6 @@ class ChatsPageState extends State<ChatsPage> {
|
|||||||
@override
|
@override
|
||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(children: <Widget>[
|
return const ChatListWidget();
|
||||||
const ChatListWidget().expanded(),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
lib/layout/home/main_pager/contacts_page.dart
Normal file
59
lib/layout/home/main_pager/contacts_page.dart
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
|
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
import '../../../contact_invitation/contact_invitation.dart';
|
||||||
|
import '../../../contacts/contacts.dart';
|
||||||
|
|
||||||
|
class ContactsPage extends StatefulWidget {
|
||||||
|
const ContactsPage({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ContactsPageState createState() => ContactsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContactsPageState extends State<ContactsPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
|
final cilState = context.watch<ContactInvitationListCubit>().state;
|
||||||
|
final cilBusy = cilState.busy;
|
||||||
|
final contactInvitationRecordList =
|
||||||
|
cilState.state.asData?.value.map((x) => x.value).toIList() ??
|
||||||
|
const IListConst([]);
|
||||||
|
|
||||||
|
final ciState = context.watch<ContactListCubit>().state;
|
||||||
|
final ciBusy = ciState.busy;
|
||||||
|
final contactList =
|
||||||
|
ciState.state.asData?.value.map((x) => x.value).toIList() ??
|
||||||
|
const IListConst([]);
|
||||||
|
|
||||||
|
return CustomScrollView(slivers: [
|
||||||
|
if (contactInvitationRecordList.isNotEmpty)
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
|
sliver: ContactInvitationListWidget(
|
||||||
|
contactInvitationRecordList: contactInvitationRecordList,
|
||||||
|
disabled: cilBusy)),
|
||||||
|
ContactListWidget(contactList: contactList, disabled: ciBusy),
|
||||||
|
]).paddingLTRB(8, 0, 8, 8);
|
||||||
|
}
|
||||||
|
}
|
@ -13,9 +13,9 @@ import 'package:provider/provider.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 'account_page.dart';
|
|
||||||
import 'bottom_sheet_action_button.dart';
|
import 'bottom_sheet_action_button.dart';
|
||||||
import 'chats_page.dart';
|
import 'chats_page.dart';
|
||||||
|
import 'contacts_page.dart';
|
||||||
|
|
||||||
class MainPager extends StatefulWidget {
|
class MainPager extends StatefulWidget {
|
||||||
const MainPager({super.key});
|
const MainPager({super.key});
|
||||||
@ -41,25 +41,6 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _onScrollNotification(ScrollNotification notification) {
|
|
||||||
if (notification is UserScrollNotification &&
|
|
||||||
notification.metrics.axis == Axis.vertical) {
|
|
||||||
switch (notification.direction) {
|
|
||||||
case ScrollDirection.forward:
|
|
||||||
// _hideBottomBarAnimationController.reverse();
|
|
||||||
// _fabAnimationController.forward(from: 0);
|
|
||||||
break;
|
|
||||||
case ScrollDirection.reverse:
|
|
||||||
// _hideBottomBarAnimationController.forward();
|
|
||||||
// _fabAnimationController.reverse(from: 1);
|
|
||||||
break;
|
|
||||||
case ScrollDirection.idle:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> scanContactInvitationDialog(BuildContext context) async {
|
Future<void> scanContactInvitationDialog(BuildContext context) async {
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
@ -162,21 +143,19 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
//extendBody: true,
|
//extendBody: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
body: NotificationListener<ScrollNotification>(
|
body: PreloadPageView(
|
||||||
onNotification: _onScrollNotification,
|
key: _pageViewKey,
|
||||||
child: PreloadPageView(
|
controller: pageController,
|
||||||
key: _pageViewKey,
|
preloadPagesCount: 2,
|
||||||
controller: pageController,
|
onPageChanged: (index) {
|
||||||
preloadPagesCount: 2,
|
setState(() {
|
||||||
onPageChanged: (index) {
|
currentPage = index;
|
||||||
setState(() {
|
});
|
||||||
currentPage = index;
|
},
|
||||||
});
|
children: const [
|
||||||
},
|
ContactsPage(),
|
||||||
children: const [
|
ChatsPage(),
|
||||||
AccountPage(),
|
]),
|
||||||
ChatsPage(),
|
|
||||||
])),
|
|
||||||
// appBar: AppBar(
|
// appBar: AppBar(
|
||||||
// toolbarHeight: 24,
|
// toolbarHeight: 24,
|
||||||
// title: Text(
|
// title: Text(
|
||||||
@ -240,7 +219,7 @@ class MainPagerState extends State<MainPager> with TickerProviderStateMixin {
|
|||||||
// ];
|
// ];
|
||||||
final _fabIconList = <IconData>[
|
final _fabIconList = <IconData>[
|
||||||
Icons.person_add_sharp,
|
Icons.person_add_sharp,
|
||||||
Icons.add_comment_sharp,
|
Icons.chat,
|
||||||
];
|
];
|
||||||
final _bottomLabelList = <String>[
|
final _bottomLabelList = <String>[
|
||||||
translate('pager.contacts'),
|
translate('pager.contacts'),
|
||||||
|
@ -11,16 +11,11 @@ class Splash extends StatefulWidget {
|
|||||||
State<Splash> createState() => _SplashState();
|
State<Splash> createState() => _SplashState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SplashState extends State<Splash> {
|
class _SplashState extends WindowSetupState<Splash> {
|
||||||
@override
|
_SplashState()
|
||||||
void initState() {
|
: super(
|
||||||
super.initState();
|
titleBarStyle: TitleBarStyle.hidden,
|
||||||
|
orientationCapability: OrientationCapability.portraitOnly);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.hidden, OrientationCapability.normal);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => PopScope(
|
Widget build(BuildContext context) => PopScope(
|
||||||
|
@ -7,7 +7,6 @@ import 'package:go_router/go_router.dart';
|
|||||||
|
|
||||||
import '../layout/default_app_bar.dart';
|
import '../layout/default_app_bar.dart';
|
||||||
import '../theme/theme.dart';
|
import '../theme/theme.dart';
|
||||||
import '../tools/tools.dart';
|
|
||||||
import '../veilid_processor/veilid_processor.dart';
|
import '../veilid_processor/veilid_processor.dart';
|
||||||
import 'settings.dart';
|
import 'settings.dart';
|
||||||
|
|
||||||
@ -26,11 +25,6 @@ class SettingsPageState extends State<SettingsPage> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.normal, OrientationCapability.normal);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -12,7 +12,7 @@ class StyledScaffold extends StatelessWidget {
|
|||||||
final scale = theme.extension<ScaleScheme>()!;
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
final scaleConfig = theme.extension<ScaleConfig>()!;
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
|
||||||
return isDesktop
|
final scaffold = isDesktop
|
||||||
? clipBorder(
|
? clipBorder(
|
||||||
clipEnabled: true,
|
clipEnabled: true,
|
||||||
borderEnabled: scaleConfig.useVisualIndicators,
|
borderEnabled: scaleConfig.useVisualIndicators,
|
||||||
@ -21,6 +21,10 @@ class StyledScaffold extends StatelessWidget {
|
|||||||
child: Scaffold(appBar: appBar, body: body, key: key))
|
child: Scaffold(appBar: appBar, body: body, key: key))
|
||||||
.paddingAll(32)
|
.paddingAll(32)
|
||||||
: Scaffold(appBar: appBar, body: body, key: key);
|
: Scaffold(appBar: appBar, body: body, key: key);
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
child: scaffold);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:async_tools/async_tools.dart';
|
import 'package:async_tools/async_tools.dart';
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
|
import 'package:bloc_advanced_tools/bloc_advanced_tools.dart';
|
||||||
@ -5,8 +7,10 @@ import 'package:blurry_modal_progress_hud/blurry_modal_progress_hud.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_spinkit/flutter_spinkit.dart';
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:flutter_sticky_header/flutter_sticky_header.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 'package:sliver_expandable/sliver_expandable.dart';
|
||||||
|
|
||||||
import '../theme.dart';
|
import '../theme.dart';
|
||||||
|
|
||||||
@ -132,7 +136,7 @@ void showErrorToast(BuildContext context, String message) {
|
|||||||
contentPadding: const EdgeInsets.all(16),
|
contentPadding: const EdgeInsets.all(16),
|
||||||
primaryColor: scale.errorScale.elementBackground,
|
primaryColor: scale.errorScale.elementBackground,
|
||||||
secondaryColor: scale.errorScale.calloutBackground,
|
secondaryColor: scale.errorScale.calloutBackground,
|
||||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
borderRadius: 12 * scaleConfig.borderRadiusScale,
|
||||||
toastDuration: const Duration(seconds: 4),
|
toastDuration: const Duration(seconds: 4),
|
||||||
animationDuration: const Duration(milliseconds: 1000),
|
animationDuration: const Duration(milliseconds: 1000),
|
||||||
displayBorder: scaleConfig.useVisualIndicators,
|
displayBorder: scaleConfig.useVisualIndicators,
|
||||||
@ -152,7 +156,7 @@ void showInfoToast(BuildContext context, String message) {
|
|||||||
contentPadding: const EdgeInsets.all(16),
|
contentPadding: const EdgeInsets.all(16),
|
||||||
primaryColor: scale.tertiaryScale.elementBackground,
|
primaryColor: scale.tertiaryScale.elementBackground,
|
||||||
secondaryColor: scale.tertiaryScale.calloutBackground,
|
secondaryColor: scale.tertiaryScale.calloutBackground,
|
||||||
borderRadius: 16 * scaleConfig.borderRadiusScale,
|
borderRadius: 12 * scaleConfig.borderRadiusScale,
|
||||||
toastDuration: const Duration(seconds: 2),
|
toastDuration: const Duration(seconds: 2),
|
||||||
animationDuration: const Duration(milliseconds: 500),
|
animationDuration: const Duration(milliseconds: 500),
|
||||||
displayBorder: scaleConfig.useVisualIndicators,
|
displayBorder: scaleConfig.useVisualIndicators,
|
||||||
@ -160,6 +164,159 @@ void showInfoToast(BuildContext context, String message) {
|
|||||||
).show(context);
|
).show(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SliverAppBar styledSliverAppBar(
|
||||||
|
{required BuildContext context, required String title, Color? titleColor}) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
//final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
|
return SliverAppBar(
|
||||||
|
title: Text(
|
||||||
|
title,
|
||||||
|
style: textTheme.titleSmall!
|
||||||
|
.copyWith(color: titleColor ?? scale.primaryScale.borderText),
|
||||||
|
),
|
||||||
|
pinned: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget styledHeaderSliver(
|
||||||
|
{required BuildContext context,
|
||||||
|
required String title,
|
||||||
|
required Widget sliver,
|
||||||
|
Color? borderColor,
|
||||||
|
Color? innerColor,
|
||||||
|
Color? titleColor,
|
||||||
|
Color? backgroundColor,
|
||||||
|
void Function()? onTap}) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
|
return SliverStickyHeader(
|
||||||
|
header: ColoredBox(
|
||||||
|
color: backgroundColor ?? Colors.transparent,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: borderColor ?? scale.primaryScale.border,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft:
|
||||||
|
Radius.circular(12 * scaleConfig.borderRadiusScale),
|
||||||
|
topRight: Radius.circular(
|
||||||
|
12 * scaleConfig.borderRadiusScale)))),
|
||||||
|
child: ListTile(
|
||||||
|
onTap: onTap,
|
||||||
|
title: Text(title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: textTheme.titleSmall!.copyWith(
|
||||||
|
color: titleColor ?? scale.primaryScale.borderText)),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
sliver: DecoratedSliver(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: borderColor ?? scale.primaryScale.border,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft:
|
||||||
|
Radius.circular(8 * scaleConfig.borderRadiusScale),
|
||||||
|
bottomRight:
|
||||||
|
Radius.circular(8 * scaleConfig.borderRadiusScale)))),
|
||||||
|
sliver: SliverPadding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
sliver: DecoratedSliver(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: innerColor ?? scale.primaryScale.subtleBackground,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale))),
|
||||||
|
sliver: SliverPadding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
sliver: sliver,
|
||||||
|
)))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget styledExpandingSliver(
|
||||||
|
{required BuildContext context,
|
||||||
|
required String title,
|
||||||
|
required Widget sliver,
|
||||||
|
required bool expanded,
|
||||||
|
required Animation<double> animation,
|
||||||
|
Color? borderColor,
|
||||||
|
Color? innerColor,
|
||||||
|
Color? titleColor,
|
||||||
|
Color? backgroundColor,
|
||||||
|
void Function()? onTap}) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final scale = theme.extension<ScaleScheme>()!;
|
||||||
|
final scaleConfig = theme.extension<ScaleConfig>()!;
|
||||||
|
final textTheme = theme.textTheme;
|
||||||
|
|
||||||
|
return SliverStickyHeader(
|
||||||
|
header: ColoredBox(
|
||||||
|
color: backgroundColor ?? Colors.transparent,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: borderColor ?? scale.primaryScale.border,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: expanded
|
||||||
|
? BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(
|
||||||
|
12 * scaleConfig.borderRadiusScale),
|
||||||
|
topRight: Radius.circular(
|
||||||
|
12 * scaleConfig.borderRadiusScale))
|
||||||
|
: BorderRadius.circular(
|
||||||
|
12 * scaleConfig.borderRadiusScale))),
|
||||||
|
child: ListTile(
|
||||||
|
onTap: onTap,
|
||||||
|
title: Text(title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: textTheme.titleSmall!.copyWith(
|
||||||
|
color: titleColor ?? scale.primaryScale.borderText)),
|
||||||
|
trailing: AnimatedBuilder(
|
||||||
|
animation: animation,
|
||||||
|
builder: (context, child) => Transform.rotate(
|
||||||
|
angle: (animation.value - 0.5) * pi,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
child: Icon(Icons.chevron_left,
|
||||||
|
color: borderColor ?? scale.primaryScale.borderText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
sliver: SliverExpandable(
|
||||||
|
sliver: DecoratedSliver(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color: borderColor ?? scale.primaryScale.border,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: expanded
|
||||||
|
? BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale),
|
||||||
|
bottomRight: Radius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale))
|
||||||
|
: BorderRadius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale))),
|
||||||
|
sliver: SliverPadding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
sliver: DecoratedSliver(
|
||||||
|
decoration: ShapeDecoration(
|
||||||
|
color:
|
||||||
|
innerColor ?? scale.primaryScale.subtleBackground,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
8 * scaleConfig.borderRadiusScale))),
|
||||||
|
sliver: SliverPadding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
sliver: sliver,
|
||||||
|
)))),
|
||||||
|
animation: animation,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Widget styledTitleContainer({
|
Widget styledTitleContainer({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required String title,
|
required String title,
|
||||||
@ -178,7 +335,7 @@ Widget styledTitleContainer({
|
|||||||
color: borderColor ?? scale.primaryScale.border,
|
color: borderColor ?? scale.primaryScale.border,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(16 * scaleConfig.borderRadiusScale),
|
BorderRadius.circular(12 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Text(
|
Text(
|
||||||
@ -192,7 +349,7 @@ Widget styledTitleContainer({
|
|||||||
backgroundColor ?? scale.primaryScale.subtleBackground,
|
backgroundColor ?? scale.primaryScale.subtleBackground,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
16 * scaleConfig.borderRadiusScale),
|
12 * scaleConfig.borderRadiusScale),
|
||||||
)),
|
)),
|
||||||
child: child)
|
child: child)
|
||||||
.paddingAll(4)
|
.paddingAll(4)
|
||||||
|
111
lib/tools/native_safe_area.dart
Normal file
111
lib/tools/native_safe_area.dart
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:native_device_orientation/native_device_orientation.dart';
|
||||||
|
|
||||||
|
class NativeSafeArea extends StatelessWidget {
|
||||||
|
const NativeSafeArea({
|
||||||
|
required this.child,
|
||||||
|
this.left = true,
|
||||||
|
this.top = true,
|
||||||
|
this.right = true,
|
||||||
|
this.bottom = true,
|
||||||
|
this.minimum = EdgeInsets.zero,
|
||||||
|
this.maintainBottomViewPadding = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Whether to avoid system intrusions on the left.
|
||||||
|
final bool left;
|
||||||
|
|
||||||
|
/// Whether to avoid system intrusions at the top of the screen, typically the
|
||||||
|
/// system status bar.
|
||||||
|
final bool top;
|
||||||
|
|
||||||
|
/// Whether to avoid system intrusions on the right.
|
||||||
|
final bool right;
|
||||||
|
|
||||||
|
/// Whether to avoid system intrusions on the bottom side of the screen.
|
||||||
|
final bool bottom;
|
||||||
|
|
||||||
|
/// This minimum padding to apply.
|
||||||
|
///
|
||||||
|
/// The greater of the minimum insets and the media padding will be applied.
|
||||||
|
final EdgeInsets minimum;
|
||||||
|
|
||||||
|
/// Specifies whether the [SafeArea] should maintain the bottom
|
||||||
|
/// [MediaQueryData.viewPadding] instead of the bottom
|
||||||
|
/// [MediaQueryData.padding], defaults to false.
|
||||||
|
///
|
||||||
|
/// For example, if there is an onscreen keyboard displayed above the
|
||||||
|
/// SafeArea, the padding can be maintained below the obstruction rather than
|
||||||
|
/// being consumed. This can be helpful in cases where your layout contains
|
||||||
|
/// flexible widgets, which could visibly move when opening a software
|
||||||
|
/// keyboard due to the change in the padding value. Setting this to true will
|
||||||
|
/// avoid the UI shift.
|
||||||
|
final bool maintainBottomViewPadding;
|
||||||
|
|
||||||
|
/// The widget below this widget in the tree.
|
||||||
|
///
|
||||||
|
/// The padding on the [MediaQuery] for the [child] will be suitably adjusted
|
||||||
|
/// to zero out any sides that were avoided by this widget.
|
||||||
|
///
|
||||||
|
/// {@macro flutter.widgets.ProxyWidget.child}
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final nativeOrientation =
|
||||||
|
NativeDeviceOrientationReader.orientation(context);
|
||||||
|
|
||||||
|
late final bool realLeft;
|
||||||
|
late final bool realRight;
|
||||||
|
late final bool realTop;
|
||||||
|
late final bool realBottom;
|
||||||
|
|
||||||
|
switch (nativeOrientation) {
|
||||||
|
case NativeDeviceOrientation.unknown:
|
||||||
|
case NativeDeviceOrientation.portraitUp:
|
||||||
|
realLeft = left;
|
||||||
|
realRight = right;
|
||||||
|
realTop = top;
|
||||||
|
realBottom = bottom;
|
||||||
|
case NativeDeviceOrientation.portraitDown:
|
||||||
|
realLeft = right;
|
||||||
|
realRight = left;
|
||||||
|
realTop = bottom;
|
||||||
|
realBottom = top;
|
||||||
|
case NativeDeviceOrientation.landscapeRight:
|
||||||
|
realLeft = bottom;
|
||||||
|
realRight = top;
|
||||||
|
realTop = left;
|
||||||
|
realBottom = right;
|
||||||
|
case NativeDeviceOrientation.landscapeLeft:
|
||||||
|
realLeft = top;
|
||||||
|
realRight = bottom;
|
||||||
|
realTop = right;
|
||||||
|
realBottom = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
left: realLeft,
|
||||||
|
right: realRight,
|
||||||
|
top: realTop,
|
||||||
|
bottom: realBottom,
|
||||||
|
minimum: minimum,
|
||||||
|
maintainBottomViewPadding: maintainBottomViewPadding,
|
||||||
|
child: child);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(DiagnosticsProperty<bool>('left', left))
|
||||||
|
..add(DiagnosticsProperty<bool>('top', top))
|
||||||
|
..add(DiagnosticsProperty<bool>('right', right))
|
||||||
|
..add(DiagnosticsProperty<bool>('bottom', bottom))
|
||||||
|
..add(DiagnosticsProperty<EdgeInsets>('minimum', minimum))
|
||||||
|
..add(DiagnosticsProperty<bool>(
|
||||||
|
'maintainBottomViewPadding', maintainBottomViewPadding));
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,13 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
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/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import '../theme/views/responsive.dart';
|
import '../theme/views/responsive.dart';
|
||||||
|
import 'tools.dart';
|
||||||
|
|
||||||
export 'package:window_manager/window_manager.dart' show TitleBarStyle;
|
export 'package:window_manager/window_manager.dart' show TitleBarStyle;
|
||||||
|
|
||||||
@ -27,7 +30,7 @@ Future<void> initializeWindowControl() async {
|
|||||||
skipTaskbar: false,
|
skipTaskbar: false,
|
||||||
);
|
);
|
||||||
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
await windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
await changeWindowSetup(
|
await _asyncChangeWindowSetup(
|
||||||
TitleBarStyle.hidden, OrientationCapability.normal);
|
TitleBarStyle.hidden, OrientationCapability.normal);
|
||||||
await windowManager.show();
|
await windowManager.show();
|
||||||
await windowManager.focus();
|
await windowManager.focus();
|
||||||
@ -35,7 +38,9 @@ Future<void> initializeWindowControl() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> changeWindowSetup(TitleBarStyle titleBarStyle,
|
const kWindowSetup = '__windowSetup';
|
||||||
|
|
||||||
|
Future<void> _asyncChangeWindowSetup(TitleBarStyle titleBarStyle,
|
||||||
OrientationCapability orientationCapability) async {
|
OrientationCapability orientationCapability) async {
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
await windowManager.setTitleBarStyle(titleBarStyle);
|
await windowManager.setTitleBarStyle(titleBarStyle);
|
||||||
@ -59,3 +64,47 @@ Future<void> changeWindowSetup(TitleBarStyle titleBarStyle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void changeWindowSetup(
|
||||||
|
TitleBarStyle titleBarStyle, OrientationCapability orientationCapability) {
|
||||||
|
singleFuture<void>(
|
||||||
|
kWindowSetup,
|
||||||
|
() async =>
|
||||||
|
_asyncChangeWindowSetup(titleBarStyle, orientationCapability));
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class WindowSetupState<T extends StatefulWidget> extends State<T> {
|
||||||
|
WindowSetupState(
|
||||||
|
{required this.titleBarStyle, required this.orientationCapability});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
changeWindowSetup(this.titleBarStyle, this.orientationCapability);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void activate() {
|
||||||
|
changeWindowSetup(this.titleBarStyle, this.orientationCapability);
|
||||||
|
super.activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void deactivate() {
|
||||||
|
changeWindowSetup(TitleBarStyle.normal, OrientationCapability.normal);
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
final TitleBarStyle titleBarStyle;
|
||||||
|
final OrientationCapability orientationCapability;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||||
|
super.debugFillProperties(properties);
|
||||||
|
properties
|
||||||
|
..add(EnumProperty<TitleBarStyle>('titleBarStyle', titleBarStyle))
|
||||||
|
..add(EnumProperty<OrientationCapability>(
|
||||||
|
'orientationCapability', orientationCapability));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:ansicolor/ansicolor.dart';
|
import 'package:ansicolor/ansicolor.dart';
|
||||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||||
import 'package:cool_dropdown/cool_dropdown.dart';
|
import 'package:cool_dropdown/cool_dropdown.dart';
|
||||||
@ -45,11 +47,6 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await changeWindowSetup(
|
|
||||||
TitleBarStyle.normal, OrientationCapability.normal);
|
|
||||||
});
|
|
||||||
|
|
||||||
_terminalController.addListener(() {
|
_terminalController.addListener(() {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
@ -273,61 +270,59 @@ class _DeveloperPageState extends State<DeveloperPage> {
|
|||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
onTap: () => FocusScope.of(context).unfocus(),
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
bottom: false,
|
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Stack(alignment: AlignmentDirectional.center, children: [
|
Stack(alignment: AlignmentDirectional.center, children: [
|
||||||
Image.asset('assets/images/ellet.png'),
|
Image.asset('assets/images/ellet.png'),
|
||||||
TerminalView(globalDebugTerminal,
|
TerminalView(globalDebugTerminal,
|
||||||
textStyle: kDefaultTerminalStyle,
|
textStyle: kDefaultTerminalStyle,
|
||||||
controller: _terminalController,
|
controller: _terminalController,
|
||||||
keyboardType: TextInputType.none,
|
keyboardType: TextInputType.none,
|
||||||
//autofocus: true,
|
//autofocus: true,
|
||||||
backgroundOpacity: _showEllet ? 0.75 : 1.0,
|
backgroundOpacity: _showEllet ? 0.75 : 1.0,
|
||||||
onSecondaryTapDown: (details, offset) async {
|
onSecondaryTapDown: (details, offset) async {
|
||||||
await copySelection(context);
|
await copySelection(context);
|
||||||
})
|
})
|
||||||
]).expanded(),
|
]).expanded(),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _debugCommandController,
|
controller: _debugCommandController,
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
8 * scaleConfig.borderRadiusScale),
|
8 * scaleConfig.borderRadiusScale),
|
||||||
borderSide: BorderSide.none),
|
borderSide: BorderSide.none),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
8 * scaleConfig.borderRadiusScale),
|
8 * scaleConfig.borderRadiusScale),
|
||||||
),
|
),
|
||||||
fillColor: scale.primaryScale.subtleBackground,
|
fillColor: scale.primaryScale.subtleBackground,
|
||||||
hintText: translate('developer.command'),
|
hintText: translate('developer.command'),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(Icons.send,
|
icon: Icon(Icons.send,
|
||||||
color: _debugCommandController.text.isEmpty
|
color: _debugCommandController.text.isEmpty
|
||||||
? scale.primaryScale.primary.withAlpha(0x3F)
|
? scale.primaryScale.primary.withAlpha(0x3F)
|
||||||
: scale.primaryScale.primary),
|
: scale.primaryScale.primary),
|
||||||
onPressed: _debugCommandController.text.isEmpty
|
onPressed: _debugCommandController.text.isEmpty
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
final debugCommand =
|
final debugCommand = _debugCommandController.text;
|
||||||
_debugCommandController.text;
|
_debugCommandController.clear();
|
||||||
_debugCommandController.clear();
|
await _sendDebugCommand(debugCommand);
|
||||||
await _sendDebugCommand(debugCommand);
|
},
|
||||||
},
|
)),
|
||||||
)),
|
onChanged: (_) {
|
||||||
onChanged: (_) {
|
setState(() => {});
|
||||||
setState(() => {});
|
},
|
||||||
},
|
onSubmitted: (debugCommand) async {
|
||||||
onSubmitted: (debugCommand) async {
|
_debugCommandController.clear();
|
||||||
_debugCommandController.clear();
|
await _sendDebugCommand(debugCommand);
|
||||||
await _sendDebugCommand(debugCommand);
|
},
|
||||||
},
|
).paddingAll(4)
|
||||||
).paddingAll(4)
|
]))));
|
||||||
]))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
72
pubspec.lock
72
pubspec.lock
@ -9,6 +9,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "67.0.0"
|
version: "67.0.0"
|
||||||
|
accordion:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: accordion
|
||||||
|
sha256: "0eca3d1c619c6df63d6e384010fd2ef1164e7385d7102f88a6b56f658f160cd0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -449,6 +457,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.0.5"
|
||||||
|
expansion_tile_group:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: expansion_tile_group
|
||||||
|
sha256: "6918433891481c7d98cbc604d7b4c93509986e8134d52940853301ad6fbff404"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.4"
|
||||||
fast_immutable_collections:
|
fast_immutable_collections:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -620,6 +636,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.1"
|
version: "5.2.1"
|
||||||
|
flutter_sticky_header:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_sticky_header
|
||||||
|
sha256: "017f398fbb45a589e01491861ca20eb6570a763fd9f3888165a978e11248c709"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.5"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -681,6 +705,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
|
get:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: get
|
||||||
|
sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.6.6"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -897,6 +929,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.10.0"
|
||||||
|
native_device_orientation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: native_device_orientation
|
||||||
|
sha256: "0c330c068575e4be72cce5968ca479a3f8d5d1e5dfce7d89d5c13a1e943b338c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1326,6 +1366,30 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.99"
|
version: "0.0.99"
|
||||||
|
sliver_expandable:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sliver_expandable
|
||||||
|
sha256: ae20eb848bd0ba9dd704732ad654438ac5a5bea2b023fa3cf80a086166d96d97
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
sliver_fill_remaining_box_adapter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sliver_fill_remaining_box_adapter
|
||||||
|
sha256: "2a222c0f09eb07c37857ce2526c0fbf3b17b2bd1b1ff0e890085f2f7a9ba1927"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
sliver_tools:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sliver_tools
|
||||||
|
sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.12"
|
||||||
smart_auth:
|
smart_auth:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1583,6 +1647,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.4.0"
|
||||||
|
value_layout_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: value_layout_builder
|
||||||
|
sha256: "98202ec1807e94ac72725b7f0d15027afde513c55c69ff3f41bcfccb950831bc"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -8,6 +8,7 @@ environment:
|
|||||||
flutter: '>=3.22.1'
|
flutter: '>=3.22.1'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
accordion: ^2.6.0
|
||||||
animated_bottom_navigation_bar: ^1.3.3
|
animated_bottom_navigation_bar: ^1.3.3
|
||||||
animated_switcher_transitions: ^1.0.0
|
animated_switcher_transitions: ^1.0.0
|
||||||
animated_theme_switcher: ^2.0.10
|
animated_theme_switcher: ^2.0.10
|
||||||
@ -27,6 +28,7 @@ dependencies:
|
|||||||
cool_dropdown: ^2.1.0
|
cool_dropdown: ^2.1.0
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
|
expansion_tile_group: ^1.2.4
|
||||||
fast_immutable_collections: ^10.2.4
|
fast_immutable_collections: ^10.2.4
|
||||||
file_saver: ^0.2.13
|
file_saver: ^0.2.13
|
||||||
fixnum: ^1.1.0
|
fixnum: ^1.1.0
|
||||||
@ -46,6 +48,7 @@ dependencies:
|
|||||||
flutter_native_splash: ^2.4.0
|
flutter_native_splash: ^2.4.0
|
||||||
flutter_slidable: ^3.1.0
|
flutter_slidable: ^3.1.0
|
||||||
flutter_spinkit: ^5.2.1
|
flutter_spinkit: ^5.2.1
|
||||||
|
flutter_sticky_header: ^0.6.5
|
||||||
flutter_svg: ^2.0.10+1
|
flutter_svg: ^2.0.10+1
|
||||||
flutter_translate: ^4.1.0
|
flutter_translate: ^4.1.0
|
||||||
flutter_zoom_drawer: ^3.2.0
|
flutter_zoom_drawer: ^3.2.0
|
||||||
@ -60,6 +63,7 @@ dependencies:
|
|||||||
meta: ^1.12.0
|
meta: ^1.12.0
|
||||||
mobile_scanner: ^5.1.1
|
mobile_scanner: ^5.1.1
|
||||||
motion_toast: ^2.10.0
|
motion_toast: ^2.10.0
|
||||||
|
native_device_orientation: ^2.0.3
|
||||||
package_info_plus: ^8.0.0
|
package_info_plus: ^8.0.0
|
||||||
pasteboard: ^0.2.0
|
pasteboard: ^0.2.0
|
||||||
path: ^1.9.0
|
path: ^1.9.0
|
||||||
@ -81,6 +85,9 @@ dependencies:
|
|||||||
share_plus: ^9.0.0
|
share_plus: ^9.0.0
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
signal_strength_indicator: ^0.4.1
|
signal_strength_indicator: ^0.4.1
|
||||||
|
sliver_expandable: ^1.1.1
|
||||||
|
sliver_fill_remaining_box_adapter: ^1.0.0
|
||||||
|
sliver_tools: ^0.2.12
|
||||||
sorted_list:
|
sorted_list:
|
||||||
git:
|
git:
|
||||||
url: https://gitlab.com/veilid/dart-sorted-list-improved.git
|
url: https://gitlab.com/veilid/dart-sorted-list-improved.git
|
||||||
|
Loading…
Reference in New Issue
Block a user