text scaling fixes

This commit is contained in:
Christien Rioux 2025-05-25 23:34:47 -04:00
parent de691cd778
commit 00fed31ce7
24 changed files with 206 additions and 238 deletions

View file

@ -267,6 +267,7 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
leading: Navigator.canPop(context) leading: Navigator.canPop(context)
? IconButton( ? IconButton(
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
iconSize: 24.scaled(context),
onPressed: () { onPressed: () {
singleFuture((this, _kDoBackArrow), () async { singleFuture((this, _kDoBackArrow), () async {
if (_isModified) { if (_isModified) {
@ -299,14 +300,14 @@ class _EditAccountPageState extends WindowSetupState<EditAccountPage> {
body: SingleChildScrollView( body: SingleChildScrollView(
child: Column(children: [ child: Column(children: [
_editAccountForm(context).paddingLTRB(0, 0, 0, 32), _editAccountForm(context).paddingLTRB(0, 0, 0, 32),
OptionBox( StyledButtonBox(
instructions: instructions:
translate('edit_account_page.remove_account_description'), translate('edit_account_page.remove_account_description'),
buttonIcon: Icons.person_remove_alt_1, buttonIcon: Icons.person_remove_alt_1,
buttonText: translate('edit_account_page.remove_account'), buttonText: translate('edit_account_page.remove_account'),
onClick: _onRemoveAccount, onClick: _onRemoveAccount,
), ),
OptionBox( StyledButtonBox(
instructions: instructions:
translate('edit_account_page.destroy_account_description'), translate('edit_account_page.destroy_account_description'),
buttonIcon: Icons.person_off, buttonIcon: Icons.person_off,

View file

@ -176,17 +176,8 @@ class _EditProfileFormState extends State<EditProfileForm> {
BuildContext context, BuildContext context,
) { ) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
late final Color border;
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
border = scale.primaryScale.elementBackground;
} else {
border = scale.primaryScale.border;
}
return FormBuilder( return FormBuilder(
key: _formKey, key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
@ -200,12 +191,7 @@ class _EditProfileFormState extends State<EditProfileForm> {
const Spacer(), const Spacer(),
StyledAvatar( StyledAvatar(
name: _currentValueName, name: _currentValueName,
size: 128, size: 128.scaled(context),
borderColor: border,
foregroundColor: scale.primaryScale.primaryText,
backgroundColor: scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!.copyWith(fontSize: 64),
).paddingLTRB(0, 0, 0, 16), ).paddingLTRB(0, 0, 0, 16),
const Spacer() const Spacer()
]), ]),
@ -327,17 +313,19 @@ class _EditProfileFormState extends State<EditProfileForm> {
false; false;
return ElevatedButton( return ElevatedButton(
onPressed: (networkReady && _isModified) ? _doSubmit : null, onPressed: (networkReady && _isModified) ? _doSubmit : null,
child: Row(mainAxisSize: MainAxisSize.min, children: [ child: Padding(
Icon(networkReady ? Icons.check : Icons.hourglass_empty, padding: EdgeInsetsGeometry.all(4.scaled(context)),
size: 16.scaled(context)) child: Row(mainAxisSize: MainAxisSize.min, children: [
.paddingLTRB(0, 0, 4.scaled(context), 0), Icon(networkReady ? Icons.check : Icons.hourglass_empty,
Text(networkReady size: 16.scaled(context))
? widget.submitText .paddingLTRB(0, 0, 4.scaled(context), 0),
: widget.submitDisabledText) Text(networkReady
.paddingLTRB(0, 0, 4.scaled(context), 0) ? widget.submitText
]), : widget.submitDisabledText)
); .paddingLTRB(0, 0, 4.scaled(context), 0)
]),
));
}), }),
const Spacer() const Spacer()
]) ])

View file

@ -194,7 +194,7 @@ class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
translate('show_recovery_key_page.instructions_options')) translate('show_recovery_key_page.instructions_options'))
.paddingLTRB(12, 0, 12, 24), .paddingLTRB(12, 0, 12, 24),
OptionBox( StyledButtonBox(
instructions: instructions:
translate('show_recovery_key_page.instructions_print'), translate('show_recovery_key_page.instructions_print'),
buttonIcon: Icons.print, buttonIcon: Icons.print,
@ -210,7 +210,7 @@ class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
_codeHandled = true; _codeHandled = true;
}); });
}), }),
OptionBox( StyledButtonBox(
instructions: instructions:
translate('show_recovery_key_page.instructions_view'), translate('show_recovery_key_page.instructions_view'),
buttonIcon: Icons.edit_document, buttonIcon: Icons.edit_document,
@ -230,7 +230,7 @@ class _ShowRecoveryKeyPageState extends WindowSetupState<ShowRecoveryKeyPage> {
_codeHandled = true; _codeHandled = true;
}); });
}), }),
OptionBox( StyledButtonBox(
instructions: instructions:
translate('show_recovery_key_page.instructions_share'), translate('show_recovery_key_page.instructions_share'),
buttonIcon: Icons.ios_share, buttonIcon: Icons.ios_share,

View file

@ -125,7 +125,7 @@ class VeilidChatApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) => FutureProvider<VeilidChatGlobalInit?>( Widget build(BuildContext context) => FutureProvider<VeilidChatGlobalInit?>(
initialData: null, initialData: null,
create: (context) async => VeilidChatGlobalInit.initialize(), create: (context) => VeilidChatGlobalInit.initialize(),
builder: (context, __) { builder: (context, __) {
final globalInit = context.watch<VeilidChatGlobalInit?>(); final globalInit = context.watch<VeilidChatGlobalInit?>();
if (globalInit == null) { if (globalInit == null) {

View file

@ -12,7 +12,7 @@ class VcTextMessageWidget extends StatelessWidget {
const VcTextMessageWidget({ const VcTextMessageWidget({
required this.message, required this.message,
required this.index, required this.index,
this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 10), this.padding,
this.borderRadius, this.borderRadius,
this.onlyEmojiFontSize, this.onlyEmojiFontSize,
this.sentBackgroundColor, this.sentBackgroundColor,
@ -72,10 +72,6 @@ class VcTextMessageWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scaleTheme = theme.extension<ScaleTheme>()!; final scaleTheme = theme.extension<ScaleTheme>()!;
final config = scaleTheme.config;
final scheme = scaleTheme.scheme;
final scale = scaleTheme.scheme.scale(ScaleKind.primary);
final textTheme = theme.textTheme;
final scaleChatTheme = scaleTheme.chatTheme(); final scaleChatTheme = scaleTheme.chatTheme();
final chatTheme = scaleChatTheme.chatTheme; final chatTheme = scaleChatTheme.chatTheme;
@ -243,15 +239,16 @@ class TimeAndStatus extends StatelessWidget {
if (showStatus && status != null) if (showStatus && status != null)
if (status == MessageStatus.sending) if (status == MessageStatus.sending)
SizedBox( SizedBox(
width: 6, width: 6.scaled(context),
height: 6, height: 6.scaled(context),
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: textStyle?.color, color: textStyle?.color,
strokeWidth: 2, strokeWidth: 2,
), ),
) )
else else
Icon(getIconForStatus(status!), color: textStyle?.color, size: 12), Icon(getIconForStatus(status!),
color: textStyle?.color, size: 12.scaled(context)),
], ],
); );
} }

View file

@ -132,17 +132,9 @@ class _ChatComponentWidgetState extends State<ChatComponentWidget> {
final scale = scaleTheme.scheme.scale(ScaleKind.primary); final scale = scaleTheme.scheme.scale(ScaleKind.primary);
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
final scaleChatTheme = scaleTheme.chatTheme(); final scaleChatTheme = scaleTheme.chatTheme();
// final errorChatTheme = chatTheme.copyWith(color:)
// ..inputTextColor = scaleScheme.errorScale.primary
// ..sendButtonIcon = Image.asset(
// 'assets/icon-send.png',
// color: scaleScheme.errorScale.primary,
// package: 'flutter_chat_ui',
// ))
// .commit();
// Get the enclosing chat component cubit that contains our state // Get the enclosing chat component cubit that contains our state
// (created by ChatComponentWidget.builder()) // (created by ChatComponentWidget.singleContact())
final chatComponentCubit = context.watch<ChatComponentCubit>(); final chatComponentCubit = context.watch<ChatComponentCubit>();
final chatComponentState = chatComponentCubit.state; final chatComponentState = chatComponentCubit.state;
@ -273,14 +265,19 @@ class _ChatComponentWidgetState extends State<ChatComponentWidget> {
// Text message builder // Text message builder
textMessageBuilder: (context, message, index) => textMessageBuilder: (context, message, index) =>
VcTextMessageWidget( VcTextMessageWidget(
message: message, message: message,
index: index, index: index,
// showTime: true, padding: const EdgeInsets.symmetric(
// showStatus: true, vertical: 12, horizontal: 16)
), .scaled(context)
// showTime: true,
// showStatus: true,
),
// Composer builder // Composer builder
composerBuilder: (ctx) => VcComposerWidget( composerBuilder: (ctx) => VcComposerWidget(
autofocus: true, autofocus: true,
padding: const EdgeInsets.all(4).scaled(context),
gap: 8.scaled(context),
focusNode: _focusNode, focusNode: _focusNode,
textInputAction: isAnyMobile textInputAction: isAnyMobile
? TextInputAction.newline ? TextInputAction.newline

View file

@ -24,11 +24,9 @@ class ChatSingleContactItemWidget extends StatelessWidget {
final bool _disabled; final bool _disabled;
@override @override
// ignore: prefer_expression_function_bodies
Widget build( Widget build(
BuildContext context, BuildContext context,
) { ) {
final theme = Theme.of(context);
final scaleTheme = Theme.of(context).extension<ScaleTheme>()!; final scaleTheme = Theme.of(context).extension<ScaleTheme>()!;
final activeChatCubit = context.watch<ActiveChatCubit>(); final activeChatCubit = context.watch<ActiveChatCubit>();
@ -50,18 +48,7 @@ class ChatSingleContactItemWidget extends StatelessWidget {
final avatar = StyledAvatar( final avatar = StyledAvatar(
name: name, name: name,
size: 32, size: 32.scaled(context),
borderColor: scaleTheme.config.useVisualIndicators
? scaleTheme.scheme.primaryScale.primaryText
: scaleTheme.scheme.primaryScale.subtleBorder,
foregroundColor: _disabled
? scaleTheme.scheme.grayScale.primaryText
: scaleTheme.scheme.primaryScale.primaryText,
backgroundColor: _disabled
? scaleTheme.scheme.grayScale.primary
: scaleTheme.scheme.primaryScale.primary,
scaleConfig: scaleTheme.config,
textStyle: theme.textTheme.titleLarge!,
); );
return StyledSlideTile( return StyledSlideTile(
@ -75,7 +62,7 @@ class ChatSingleContactItemWidget extends StatelessWidget {
trailing: AvailabilityWidget( trailing: AvailabilityWidget(
availability: availability, availability: availability,
color: scaleTileTheme.textColor, color: scaleTileTheme.textColor,
).fit(fit: BoxFit.scaleDown), ).fit(fit: BoxFit.fill),
onTap: () { onTap: () {
singleFuture(activeChatCubit, () async { singleFuture(activeChatCubit, () async {
activeChatCubit.setActiveChat(_localConversationRecordKey); activeChatCubit.setActiveChat(_localConversationRecordKey);

View file

@ -26,27 +26,13 @@ class ContactItemWidget extends StatelessWidget {
Widget build( Widget build(
BuildContext context, BuildContext context,
) { ) {
final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final name = _contact.nameOrNickname; final name = _contact.nameOrNickname;
final title = _contact.displayName; final title = _contact.displayName;
final subtitle = _contact.profile.status; final subtitle = _contact.profile.status;
final avatar = StyledAvatar( final avatar = StyledAvatar(
name: name, name: name,
size: 34, size: 34.scaled(context),
borderColor: _disabled
? scale.grayScale.primaryText
: scale.primaryScale.subtleBorder,
foregroundColor: _disabled
? scale.grayScale.primaryText
: scale.primaryScale.primaryText,
backgroundColor:
_disabled ? scale.grayScale.primary : scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!,
); );
return StyledSlideTile( return StyledSlideTile(

View file

@ -92,7 +92,7 @@ class _ContactsBrowserState extends State<ContactsBrowser>
final menuParams = StarMenuParameters( final menuParams = StarMenuParameters(
shape: MenuShape.linear, shape: MenuShape.linear,
centerOffset: const Offset(0, 64), centerOffset: Offset(0, 64.scaled(context)),
boundaryBackground: BoundaryBackground( boundaryBackground: BoundaryBackground(
color: menuBackgroundColor, color: menuBackgroundColor,
decoration: ShapeDecoration( decoration: ShapeDecoration(
@ -113,13 +113,14 @@ class _ContactsBrowserState extends State<ContactsBrowser>
onPressed: onPressed, onPressed: onPressed,
icon: Icon( icon: Icon(
iconData, iconData,
size: 32, size: 32.scaled(context),
).paddingSTEB(0, 8, 0, 8), ).paddingSTEB(0, 8.scaled(context), 0, 8.scaled(context)),
label: Text( label: Text(
text, text,
textScaler: MediaQuery.of(context).textScaler,
maxLines: 2, maxLines: 2,
textAlign: TextAlign.center, textAlign: TextAlign.center,
).paddingSTEB(0, 8, 0, 8)); ).paddingSTEB(0, 8.scaled(context), 0, 8.scaled(context)));
final inviteMenuItems = [ final inviteMenuItems = [
makeMenuButton( makeMenuButton(
@ -135,14 +136,14 @@ class _ContactsBrowserState extends State<ContactsBrowser>
onPressed: () async { onPressed: () async {
_invitationMenuController.closeMenu!(); _invitationMenuController.closeMenu!();
await ScanInvitationDialog.show(context); await ScanInvitationDialog.show(context);
}).paddingLTRB(0, 0, 0, 8), }).paddingLTRB(0, 0, 0, 8.scaled(context)),
makeMenuButton( makeMenuButton(
iconData: Icons.contact_page, iconData: Icons.contact_page,
text: translate('add_contact_sheet.create_invite'), text: translate('add_contact_sheet.create_invite'),
onPressed: () async { onPressed: () async {
_invitationMenuController.closeMenu!(); _invitationMenuController.closeMenu!();
await CreateInvitationDialog.show(context); await CreateInvitationDialog.show(context);
}).paddingLTRB(0, 0, 0, 8), }).paddingLTRB(0, 0, 0, 8.scaled(context)),
]; ];
return StarMenu( return StarMenu(
@ -154,7 +155,7 @@ class _ContactsBrowserState extends State<ContactsBrowser>
params: menuParams, params: menuParams,
child: IconButton( child: IconButton(
onPressed: () {}, onPressed: () {},
iconSize: 24, iconSize: 24.scaled(context),
icon: Icon(Icons.person_add, color: menuIconColor), icon: Icon(Icons.person_add, color: menuIconColor),
tooltip: translate('add_contact_sheet.add_contact')), tooltip: translate('add_contact_sheet.add_contact')),
); );
@ -202,13 +203,13 @@ class _ContactsBrowserState extends State<ContactsBrowser>
onDoubleTap: _onStartChat, onDoubleTap: _onStartChat,
onTap: onContactSelected, onTap: onContactSelected,
onDelete: _onContactDeleted) onDelete: _onContactDeleted)
.paddingLTRB(0, 4, 0, 0); .paddingLTRB(0, 4.scaled(context), 0, 0);
case ContactsBrowserElementKind.invitation: case ContactsBrowserElementKind.invitation:
final invitation = element.invitation!; final invitation = element.invitation!;
return ContactInvitationItemWidget( return ContactInvitationItemWidget(
contactInvitationRecord: invitation, contactInvitationRecord: invitation,
disabled: false) disabled: false)
.paddingLTRB(0, 4, 0, 0); .paddingLTRB(0, 4.scaled(context), 0, 0);
} }
}, },
filter: (value) { filter: (value) {
@ -242,9 +243,11 @@ class _ContactsBrowserState extends State<ContactsBrowser>
} }
return filtered; return filtered;
}, },
searchFieldHeight: 40, searchFieldHeight: 40.scaled(context),
listViewPadding: const EdgeInsets.fromLTRB(4, 0, 4, 4), listViewPadding:
searchFieldPadding: const EdgeInsets.fromLTRB(4, 8, 4, 4), const EdgeInsets.fromLTRB(4, 0, 4, 4).scaled(context),
searchFieldPadding:
const EdgeInsets.fromLTRB(4, 8, 4, 4).scaled(context),
emptyWidget: contactList == null emptyWidget: contactList == null
? waitingPage( ? waitingPage(
text: translate('contact_list.loading_contacts')) text: translate('contact_list.loading_contacts'))
@ -254,8 +257,8 @@ class _ContactsBrowserState extends State<ContactsBrowser>
searchFieldEnabled: contactList != null, searchFieldEnabled: contactList != null,
inputDecoration: inputDecoration:
InputDecoration(labelText: translate('contact_list.search')), InputDecoration(labelText: translate('contact_list.search')),
secondaryWidget: secondaryWidget: buildInvitationButton(context)
buildInvitationButton(context).paddingLTRB(4, 0, 0, 0)) .paddingLTRB(4.scaled(context), 0, 0, 0))
.expanded() .expanded()
]); ]);
} }

View file

@ -48,6 +48,7 @@ class _ContactsPageState extends State<ContactsPage> {
), ),
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
iconSize: 24.scaled(context),
onPressed: () { onPressed: () {
singleFuture((this, _kDoBackArrow), () async { singleFuture((this, _kDoBackArrow), () async {
final confirmed = await _onContactSelected(null); final confirmed = await _onContactSelected(null);
@ -66,21 +67,21 @@ class _ContactsPageState extends State<ContactsPage> {
if (_selectedContact != null) if (_selectedContact != null)
IconButton( IconButton(
icon: const Icon(Icons.chat_bubble), icon: const Icon(Icons.chat_bubble),
iconSize: 24, iconSize: 24.scaled(context),
color: appBarTheme.iconColor, color: appBarTheme.iconColor,
tooltip: translate('contacts_dialog.new_chat'), tooltip: translate('contacts_dialog.new_chat'),
onPressed: () async { onPressed: () async {
await _onChatStarted(_selectedContact!); await _onChatStarted(_selectedContact!);
}).paddingLTRB(8, 0, 8, 0), }),
if (enableSplit && _selectedContact != null) if (enableSplit && _selectedContact != null)
IconButton( IconButton(
icon: const Icon(Icons.close), icon: const Icon(Icons.close),
iconSize: 24, iconSize: 24.scaled(context),
color: appBarTheme.iconColor, color: appBarTheme.iconColor,
tooltip: translate('contacts_dialog.close_contact'), tooltip: translate('contacts_dialog.close_contact'),
onPressed: () async { onPressed: () async {
await _onContactSelected(null); await _onContactSelected(null);
}).paddingLTRB(8, 0, 8, 0), }),
]), ]),
body: LayoutBuilder(builder: (context, constraint) { body: LayoutBuilder(builder: (context, constraint) {
final maxWidth = constraint.maxWidth; final maxWidth = constraint.maxWidth;

View file

@ -92,16 +92,8 @@ class _EditContactFormState extends State<EditContactForm> {
Widget _editContactForm(BuildContext context) { Widget _editContactForm(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final scaleConfig = theme.extension<ScaleConfig>()!;
final textTheme = theme.textTheme; final textTheme = theme.textTheme;
late final Color border;
if (scaleConfig.useVisualIndicators && !scaleConfig.preferBorders) {
border = scale.primaryScale.elementBackground;
} else {
border = scale.primaryScale.subtleBorder;
}
return FormBuilder( return FormBuilder(
key: _formKey, key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
@ -117,17 +109,11 @@ class _EditContactFormState extends State<EditContactForm> {
Row(children: [ Row(children: [
const Spacer(), const Spacer(),
StyledAvatar( StyledAvatar(
name: _currentValueNickname.isNotEmpty name: _currentValueNickname.isNotEmpty
? _currentValueNickname ? _currentValueNickname
: widget.contact.profile.name, : widget.contact.profile.name,
size: 128, size: 128)
borderColor: border, .paddingLTRB(0, 0, 0, 16),
foregroundColor: scale.primaryScale.primaryText,
backgroundColor: scale.primaryScale.primary,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!
.copyWith(fontSize: 64),
).paddingLTRB(0, 0, 0, 16),
const Spacer() const Spacer()
]), ]),
SelectableText(widget.contact.profile.name, SelectableText(widget.contact.profile.name,
@ -211,10 +197,11 @@ class _EditContactFormState extends State<EditContactForm> {
ElevatedButton( ElevatedButton(
onPressed: _isModified ? _doSubmit : null, onPressed: _isModified ? _doSubmit : null,
child: Row(mainAxisSize: MainAxisSize.min, children: [ child: Row(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.check, size: 16).paddingLTRB(0, 0, 4, 0), Icon(Icons.check, size: 24.scaled(context))
Text(widget.submitText).paddingLTRB(0, 0, 4, 0) .paddingLTRB(0, 0, 4, 0),
]), Text(widget.submitText).paddingLTRB(0, 0, 4.scaled(context), 0)
).paddingSymmetric(vertical: 4).alignAtCenter(), ]).paddingAll(4.scaled(context)),
).paddingSymmetric(vertical: 4.scaled(context)).alignAtCenter(),
], ],
), ),
); );

View file

@ -14,6 +14,7 @@ class DefaultAppBar extends AppBar {
super.actions}) super.actions})
: super( : super(
toolbarHeight: 40.scaled(context), toolbarHeight: 40.scaled(context),
leadingWidth: 40.scaled(context),
leading: leading ?? leading: leading ??
Container( Container(
margin: const EdgeInsets.all(4).scaled(context), margin: const EdgeInsets.all(4).scaled(context),
@ -21,6 +22,7 @@ class DefaultAppBar extends AppBar {
color: Colors.black.withAlpha(32), color: Colors.black.withAlpha(32),
shape: BoxShape.circle), shape: BoxShape.circle),
child: SvgPicture.asset('assets/images/vlogo.svg', child: SvgPicture.asset('assets/images/vlogo.svg',
width: 24.scaled(context),
height: 24.scaled(context)) height: 24.scaled(context))
.paddingAll(4))); .paddingAll(4.scaled(context))));
} }

View file

@ -98,11 +98,6 @@ class _DrawerMenuState extends State<DrawerMenu> {
final avatar = StyledAvatar( final avatar = StyledAvatar(
name: name, name: name,
size: 34.scaled(context), size: 34.scaled(context),
borderColor: border,
foregroundColor: loggedIn ? scale.primaryText : scale.subtleText,
backgroundColor: loggedIn ? scale.primary : scale.elementBackground,
scaleConfig: scaleConfig,
textStyle: theme.textTheme.titleLarge!,
); );
return AnimatedPadding( return AnimatedPadding(

View file

@ -71,8 +71,9 @@ class HomeScreenState extends State<HomeScreen>
context: context, context: context,
title: translate('splash.beta_title'), title: translate('splash.beta_title'),
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
const Icon(Icons.warning, size: 64), Icon(Icons.warning, size: 64.scaled(context)),
RichText( RichText(
textScaler: MediaQuery.of(context).textScaler,
textAlign: TextAlign.center, textAlign: TextAlign.center,
text: TextSpan( text: TextSpan(
children: <TextSpan>[ children: <TextSpan>[
@ -206,34 +207,36 @@ 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;
final drawer = ZoomDrawer(
controller: _zoomDrawerController,
menuScreen: Builder(builder: (context) {
final zoomDrawer = ZoomDrawer.of(context);
zoomDrawer!.stateNotifier.addListener(() {
if (zoomDrawer.isOpen()) {
FocusManager.instance.primaryFocus?.unfocus();
}
});
return const DrawerMenu();
}),
mainScreen: Provider<ZoomDrawerController>.value(
value: _zoomDrawerController,
child: Builder(builder: _buildAccountPageView)),
borderRadius: 0,
angle: 0,
openCurve: Curves.fastEaseInToSlowEaseOut,
closeCurve: Curves.fastEaseInToSlowEaseOut,
menuScreenTapClose: canClose,
mainScreenTapClose: canClose,
disableDragGesture: !canClose,
mainScreenScale: .25,
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
);
final drawerWithAvoider =
isWeb ? drawer : KeyboardAvoider(curve: Curves.ease, child: drawer);
return DefaultTextStyle( return DefaultTextStyle(
style: theme.textTheme.bodySmall!, style: theme.textTheme.bodySmall!, child: drawerWithAvoider);
child: KeyboardAvoider(
curve: Curves.ease,
child: ZoomDrawer(
controller: _zoomDrawerController,
menuScreen: Builder(builder: (context) {
final zoomDrawer = ZoomDrawer.of(context);
zoomDrawer!.stateNotifier.addListener(() {
if (zoomDrawer.isOpen()) {
FocusManager.instance.primaryFocus?.unfocus();
}
});
return const DrawerMenu();
}),
mainScreen: Provider<ZoomDrawerController>.value(
value: _zoomDrawerController,
child: Builder(builder: _buildAccountPageView)),
borderRadius: 0,
angle: 0,
openCurve: Curves.fastEaseInToSlowEaseOut,
closeCurve: Curves.fastEaseInToSlowEaseOut,
menuScreenTapClose: canClose,
mainScreenTapClose: canClose,
disableDragGesture: !canClose,
mainScreenScale: .25,
slideWidth: min(360, MediaQuery.of(context).size.width * 0.9),
)));
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////

View file

@ -42,9 +42,10 @@ Widget buildSettingsPageNotificationPreferences(
enabled: x.$2, enabled: x.$2,
child: Text( child: Text(
x.$3, x.$3,
style: textTheme.labelSmall, softWrap: false,
style: textTheme.labelMedium,
textAlign: TextAlign.center, textAlign: TextAlign.center,
))); ).fit(fit: BoxFit.scaleDown)));
} }
return out; return out;
} }
@ -65,7 +66,8 @@ Widget buildSettingsPageNotificationPreferences(
enabled: x.$2, enabled: x.$2,
child: Text( child: Text(
x.$3, x.$3,
style: textTheme.labelSmall, softWrap: false,
style: textTheme.labelMedium,
textAlign: TextAlign.center, textAlign: TextAlign.center,
))); )));
} }
@ -98,7 +100,8 @@ Widget buildSettingsPageNotificationPreferences(
enabled: x.$2, enabled: x.$2,
child: Text( child: Text(
x.$3, x.$3,
style: textTheme.labelSmall, softWrap: false,
style: textTheme.labelMedium,
textAlign: TextAlign.center, textAlign: TextAlign.center,
))); )));
} }
@ -187,7 +190,7 @@ Widget buildSettingsPageNotificationPreferences(
Text( Text(
textAlign: TextAlign.right, textAlign: TextAlign.right,
translate('settings_page.invitation_accepted')) translate('settings_page.invitation_accepted'))
.paddingAll(8), .paddingAll(4.scaled(context)),
StyledDropdown<NotificationMode>( StyledDropdown<NotificationMode>(
items: notificationModeItems(), items: notificationModeItems(),
value: notificationsPreference.onInvitationAcceptedMode, value: notificationsPreference.onInvitationAcceptedMode,
@ -219,7 +222,7 @@ Widget buildSettingsPageNotificationPreferences(
Text( Text(
textAlign: TextAlign.right, textAlign: TextAlign.right,
translate('settings_page.message_received')) translate('settings_page.message_received'))
.paddingAll(8), .paddingAll(4.scaled(context)),
StyledDropdown<NotificationMode>( StyledDropdown<NotificationMode>(
items: notificationModeItems(), items: notificationModeItems(),
value: notificationsPreference.onMessageReceivedMode, value: notificationsPreference.onMessageReceivedMode,
@ -252,7 +255,7 @@ Widget buildSettingsPageNotificationPreferences(
Text( Text(
textAlign: TextAlign.right, textAlign: TextAlign.right,
translate('settings_page.message_sent')) translate('settings_page.message_sent'))
.paddingAll(8.scaled(context)), .paddingAll(4.scaled(context)),
const SizedBox.shrink(), const SizedBox.shrink(),
StyledDropdown<SoundEffect>( StyledDropdown<SoundEffect>(
items: soundEffectItems(), items: soundEffectItems(),

View file

@ -22,7 +22,8 @@ class SettingsPage extends StatelessWidget {
context: context, context: context,
title: Text(translate('settings_page.titlebar')), title: Text(translate('settings_page.titlebar')),
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back), iconSize: 24.scaled(context),
icon: Icon(Icons.arrow_back),
onPressed: () => GoRouterHelper(context).pop(), onPressed: () => GoRouterHelper(context).pop(),
), ),
actions: <Widget>[ actions: <Widget>[

View file

@ -29,9 +29,9 @@ const _scaleNames = [
]; ];
const _scaleNumMult = <double>[ const _scaleNumMult = <double>[
1, 1 / (1 + 1 / 2),
1, 1 / (1 + 1 / 3),
1, 1 / (1 + 1 / 4),
1, 1,
1 + 1 / 4, 1 + 1 / 4,
1 + 1 / 2, 1 + 1 / 2,

View file

@ -8,24 +8,31 @@ class StyledAvatar extends StatelessWidget {
const StyledAvatar({ const StyledAvatar({
required String name, required String name,
required double size, required double size,
required Color borderColor, bool enabled = true,
required Color foregroundColor,
required Color backgroundColor,
required ScaleConfig scaleConfig,
required TextStyle textStyle,
super.key, super.key,
ImageProvider<Object>? imageProvider, ImageProvider<Object>? imageProvider,
}) : _name = name, }) : _name = name,
_size = size, _size = size,
_borderColor = borderColor, _imageProvider = imageProvider,
_foregroundColor = foregroundColor, _enabled = enabled;
_backgroundColor = backgroundColor,
_scaleConfig = scaleConfig,
_textStyle = textStyle,
_imageProvider = imageProvider;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
final scaleTheme = Theme.of(context).extension<ScaleTheme>()!;
final borderColor = scaleTheme.config.useVisualIndicators
? scaleTheme.scheme.primaryScale.primaryText
: scaleTheme.scheme.primaryScale.subtleBorder;
final foregroundColor = !_enabled
? scaleTheme.scheme.grayScale.primaryText
: scaleTheme.scheme.primaryScale.calloutText;
final backgroundColor = !_enabled
? scaleTheme.scheme.grayScale.primary
: scaleTheme.scheme.primaryScale.calloutBackground;
final scaleConfig = scaleTheme.config;
final textStyle = theme.textTheme.titleLarge!.copyWith(fontSize: _size / 2);
final abbrev = _name.split(' ').map((s) => s.isEmpty ? '' : s[0]).join(); final abbrev = _name.split(' ').map((s) => s.isEmpty ? '' : s[0]).join();
late final String shortname; late final String shortname;
if (abbrev.length >= 3) { if (abbrev.length >= 3) {
@ -39,35 +46,32 @@ class StyledAvatar extends StatelessWidget {
width: _size, width: _size,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: !scaleConfig.useVisualIndicators
color: _borderColor, ? null
width: 1 * (_size ~/ 32 + 1), : Border.all(
strokeAlign: BorderSide.strokeAlignOutside)), color: borderColor,
width: 1 * (_size ~/ 16 + 1),
strokeAlign: BorderSide.strokeAlignOutside)),
child: AvatarImage( child: AvatarImage(
backgroundImage: _imageProvider, backgroundImage: _imageProvider,
backgroundColor: backgroundColor: scaleConfig.useVisualIndicators
_scaleConfig.useVisualIndicators && !_scaleConfig.preferBorders ? foregroundColor
? _foregroundColor : backgroundColor,
: _backgroundColor,
child: Text( child: Text(
shortname.isNotEmpty ? shortname : '?', shortname.isNotEmpty ? shortname : '?',
softWrap: false, softWrap: false,
style: _textStyle.copyWith( textScaler: MediaQuery.of(context).textScaler,
color: _scaleConfig.useVisualIndicators && style: textStyle.copyWith(
!_scaleConfig.preferBorders color: scaleConfig.useVisualIndicators
? _backgroundColor ? backgroundColor
: _foregroundColor, : foregroundColor,
), ),
).fit().paddingAll(_size / 16.scaled(context)))); ).paddingAll(4.scaled(context)).fit(fit: BoxFit.scaleDown)));
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
final String _name; final String _name;
final double _size; final double _size;
final Color _borderColor;
final Color _foregroundColor;
final Color _backgroundColor;
final ScaleConfig _scaleConfig;
final TextStyle _textStyle;
final ImageProvider<Object>? _imageProvider; final ImageProvider<Object>? _imageProvider;
final bool _enabled;
} }

View file

@ -1,10 +1,10 @@
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 '../theme.dart'; import '../../theme.dart';
class OptionBox extends StatelessWidget { class StyledButtonBox extends StatelessWidget {
const OptionBox( const StyledButtonBox(
{required String instructions, {required String instructions,
required IconData buttonIcon, required IconData buttonIcon,
required String buttonText, required String buttonText,
@ -41,12 +41,15 @@ class OptionBox extends StatelessWidget {
onPressed: _onClick, onPressed: _onClick,
child: Row(mainAxisSize: MainAxisSize.min, children: [ child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(_buttonIcon, Icon(_buttonIcon,
size: 24, color: scale.primaryScale.appText) size: 24.scaled(context),
.paddingLTRB(0, 8, 8, 8), color: scale.primaryScale.appText)
.paddingLTRB(0, 8.scaled(context),
8.scaled(context), 8.scaled(context)),
Text(textAlign: TextAlign.center, _buttonText) Text(textAlign: TextAlign.center, _buttonText)
])).paddingLTRB(0, 12, 0, 0).toCenter() ])).paddingLTRB(0, 12.scaled(context), 0, 0).toCenter()
]).paddingAll(12)) ]).paddingAll(12.scaled(context)))
.paddingLTRB(24, 0, 24, 12); .paddingLTRB(
24.scaled(context), 0, 24.scaled(context), 12.scaled(context));
} }
final String _instructions; final String _instructions;

View file

@ -29,19 +29,21 @@ class StyledCheckbox extends StatelessWidget {
} }
Widget ctrl = Row(children: [ Widget ctrl = Row(children: [
Checkbox( Transform.scale(
value: _value, scale: 1.scaled(context),
onChanged: _onChanged == null child: Checkbox(
? null value: _value,
: (value) { onChanged: _onChanged == null
if (value == null) { ? null
return; : (value) {
} if (value == null) {
singleFuture((this, _kStyledCheckboxChanged), () async { return;
await _onChanged(value); }
}); singleFuture((this, _kStyledCheckboxChanged), () async {
}), await _onChanged(value);
Text(_label, style: textStyle), });
})),
Text(_label, style: textStyle).paddingAll(4.scaled(context)),
]); ]);
if (_decoratorLabel != null) { if (_decoratorLabel != null) {

View file

@ -33,6 +33,7 @@ class StyledDropdown<T> extends StatelessWidget {
iconDisabledColor: scheme.primaryScale.appText.withAlpha(127), iconDisabledColor: scheme.primaryScale.appText.withAlpha(127),
items: _items, items: _items,
value: _value, value: _value,
style: theme.textTheme.labelLarge,
onChanged: _onChanged == null onChanged: _onChanged == null
? null ? null
: (value) { : (value) {

View file

@ -66,7 +66,6 @@ class StyledSlideTile extends StatelessWidget {
} }
@override @override
// ignore: prefer_expression_function_bodies
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final scaleTheme = theme.extension<ScaleTheme>()!; final scaleTheme = theme.extension<ScaleTheme>()!;
@ -91,12 +90,13 @@ class StyledSlideTile extends StatelessWidget {
selected: true, selected: true,
scaleKind: a.actionScale); scaleKind: a.actionScale);
return SlidableAction( return SlidableAction(
onPressed: disabled ? null : a.onPressed, onPressed: disabled ? null : a.onPressed,
backgroundColor: scaleActionTheme.backgroundColor, backgroundColor: scaleActionTheme.backgroundColor,
foregroundColor: scaleActionTheme.textColor, foregroundColor: scaleActionTheme.textColor,
icon: subtitle.isEmpty ? a.icon : null, icon: subtitle.isEmpty ? a.icon : null,
label: a.label, label: a.label,
padding: const EdgeInsets.all(2)); padding: const EdgeInsets.all(2).scaled(context),
);
}).toList()), }).toList()),
startActionPane: startActions.isEmpty startActionPane: startActions.isEmpty
? null ? null
@ -109,17 +109,18 @@ class StyledSlideTile extends StatelessWidget {
scaleKind: a.actionScale); scaleKind: a.actionScale);
return SlidableAction( return SlidableAction(
onPressed: disabled ? null : a.onPressed, onPressed: disabled ? null : a.onPressed,
backgroundColor: scaleActionTheme.backgroundColor, backgroundColor: scaleActionTheme.backgroundColor,
foregroundColor: scaleActionTheme.textColor, foregroundColor: scaleActionTheme.textColor,
icon: subtitle.isEmpty ? a.icon : null, icon: subtitle.isEmpty ? a.icon : null,
label: a.label, label: a.label,
padding: const EdgeInsets.all(2)); padding: const EdgeInsets.all(2).scaled(context),
);
}).toList()), }).toList()),
child: Padding( child: Padding(
padding: scaleTheme.config.useVisualIndicators padding: scaleTheme.config.useVisualIndicators
? EdgeInsets.zero ? EdgeInsets.zero
: const EdgeInsets.fromLTRB(0, 2, 0, 2), : const EdgeInsets.fromLTRB(0, 2, 0, 2).scaled(context),
child: GestureDetector( child: GestureDetector(
onDoubleTap: onDoubleTap, onDoubleTap: onDoubleTap,
child: ListTile( child: ListTile(
@ -131,7 +132,8 @@ class StyledSlideTile extends StatelessWidget {
softWrap: false, softWrap: false,
), ),
subtitle: subtitle.isNotEmpty ? Text(subtitle) : null, subtitle: subtitle.isNotEmpty ? Text(subtitle) : null,
minTileHeight: 52, contentPadding: const EdgeInsets.fromLTRB(8, 4, 8, 4)
.scaled(context),
iconColor: scaleTileTheme.textColor, iconColor: scaleTileTheme.textColor,
textColor: scaleTileTheme.textColor, textColor: scaleTileTheme.textColor,
leading: leading:

View file

@ -1,10 +1,10 @@
export 'enter_password.dart'; export 'enter_password.dart';
export 'enter_pin.dart'; export 'enter_pin.dart';
export 'option_box.dart';
export 'pop_control.dart'; export 'pop_control.dart';
export 'preferences/preferences.dart'; export 'preferences/preferences.dart';
export 'recovery_key_widget.dart'; export 'recovery_key_widget.dart';
export 'responsive.dart'; export 'responsive.dart';
export 'scanner_error_widget.dart'; export 'scanner_error_widget.dart';
export 'styled_widgets/styled_button_box.dart';
export 'styled_widgets/styled_widgets.dart'; export 'styled_widgets/styled_widgets.dart';
export 'widget_helpers.dart'; export 'widget_helpers.dart';

View file

@ -225,11 +225,13 @@ class _DeveloperPageState extends State<DeveloperPage> {
context: context, context: context,
title: Text(translate('developer.title')), title: Text(translate('developer.title')),
leading: IconButton( leading: IconButton(
iconSize: 24.scaled(context),
icon: Icon(Icons.arrow_back, color: scale.primaryScale.borderText), icon: Icon(Icons.arrow_back, color: scale.primaryScale.borderText),
onPressed: () => GoRouterHelper(context).pop(), onPressed: () => GoRouterHelper(context).pop(),
), ),
actions: [ actions: [
IconButton( IconButton(
iconSize: 24.scaled(context),
icon: const Icon(Icons.copy), icon: const Icon(Icons.copy),
color: scale.primaryScale.borderText, color: scale.primaryScale.borderText,
disabledColor: scale.primaryScale.borderText.withAlpha(0x3F), disabledColor: scale.primaryScale.borderText.withAlpha(0x3F),
@ -239,6 +241,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
await copySelection(context); await copySelection(context);
}), }),
IconButton( IconButton(
iconSize: 24.scaled(context),
icon: const Icon(Icons.copy_all), icon: const Icon(Icons.copy_all),
color: scale.primaryScale.borderText, color: scale.primaryScale.borderText,
disabledColor: scale.primaryScale.borderText.withAlpha(0x3F), disabledColor: scale.primaryScale.borderText.withAlpha(0x3F),
@ -246,6 +249,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
await copyAll(context); await copyAll(context);
}), }),
IconButton( IconButton(
iconSize: 24.scaled(context),
icon: const Icon(Icons.clear_all), icon: const Icon(Icons.clear_all),
color: scale.primaryScale.borderText, color: scale.primaryScale.borderText,
disabledColor: scale.primaryScale.borderText.withAlpha(0x3F), disabledColor: scale.primaryScale.borderText.withAlpha(0x3F),
@ -260,7 +264,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
} }
}), }),
SizedBox.fromSize( SizedBox.fromSize(
size: const Size(140, 48), size: Size(140.scaled(context), 48),
child: CustomDropdown<LogLevelDropdownItem>( child: CustomDropdown<LogLevelDropdownItem>(
items: _logLevelDropdownItems, items: _logLevelDropdownItems,
initialItem: _logLevelDropdownItems initialItem: _logLevelDropdownItems
@ -301,6 +305,7 @@ class _DeveloperPageState extends State<DeveloperPage> {
Image.asset('assets/images/ellet.png'), Image.asset('assets/images/ellet.png'),
TerminalView(globalDebugTerminal, TerminalView(globalDebugTerminal,
textStyle: kDefaultTerminalStyle, textStyle: kDefaultTerminalStyle,
textScaler: TextScaler.noScaling,
controller: _terminalController, controller: _terminalController,
keyboardType: TextInputType.none, keyboardType: TextInputType.none,
backgroundOpacity: _showEllet ? 0.75 : 1.0, backgroundOpacity: _showEllet ? 0.75 : 1.0,