Improved: UI components adapt to native styling

This commit is contained in:
otsmr 2026-05-31 02:22:28 +02:00
parent 9beb8ef9d7
commit 9e28bb82a2
42 changed files with 62 additions and 61 deletions

View file

@ -3,7 +3,8 @@
## 0.2.25
- New: Import images from the gallery
- Improves: Media files are now stored in the "twonly" album
- Improved: Media files are now stored in the dedicated "twonly" album
- Improved: UI components adapt to native styling (iOS/Android)
- Fix: Migration issue that resulted in a corrupted backup mechanism
- Fix: Database issues causing messages to be lost or the database to be corrupted
- Fix: Permission view did not disappear after they were granted

View file

@ -54,7 +54,7 @@ class _VideoPlayerFileHelperState extends State<VideoPlayerFileHelper> {
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayerHelper(controller: _controller),
)
: const CircularProgressIndicator(),
: const CircularProgressIndicator.adaptive(),
);
}
}

View file

@ -260,7 +260,7 @@ class _StartNewChatView extends State<AddNewShortcutView> {
group: group,
fontSize: 15,
),
trailing: Checkbox(
trailing: Checkbox.adaptive(
value: _selectedGroups.contains(group.groupId),
side: WidgetStateBorderSide.resolveWith(
(states) {

View file

@ -75,7 +75,7 @@ class CameraScannedOverlay extends StatelessWidget {
const SizedBox(
width: 12,
height: 12,
child: CircularProgressIndicator(strokeWidth: 2),
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
)
else
ColoredBox(

View file

@ -90,7 +90,7 @@ class SaveToGalleryButtonState extends State<SaveToGalleryButton> {
const SizedBox(
width: 12,
height: 12,
child: CircularProgressIndicator(strokeWidth: 1),
child: CircularProgressIndicator.adaptive(strokeWidth: 1),
)
else
_imageSaved

View file

@ -218,7 +218,7 @@ class _ShareImageView extends State<ShareImageView> {
),
Transform.scale(
scale: 0.75,
child: Checkbox(
child: Checkbox.adaptive(
value: !hideArchivedUsers,
side: WidgetStateBorderSide.resolveWith(
(states) {
@ -293,9 +293,9 @@ class _ShareImageView extends State<ShareImageView> {
? SizedBox(
height: 12,
width: 12,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
color: Theme.of(context).colorScheme.inversePrimary,
valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.inversePrimary),
),
)
: const FaIcon(FontAwesomeIcons.solidPaperPlane),
@ -382,7 +382,7 @@ class UserList extends StatelessWidget {
group: group,
fontSize: 15,
),
trailing: Checkbox(
trailing: Checkbox.adaptive(
value: selectedGroupIds.contains(group.groupId),
side: WidgetStateBorderSide.resolveWith(
(states) {

View file

@ -165,7 +165,7 @@ class UserCheckbox extends StatelessWidget {
],
),
Expanded(child: Container()),
Checkbox(
Checkbox.adaptive(
value: isChecked,
side: WidgetStateBorderSide.resolveWith(
(states) {

View file

@ -68,7 +68,7 @@ class _SelectShowTimeState extends State<SelectShowTime> {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(
Checkbox.adaptive(
value: _storeAsDefault,
onChanged: (value) => setState(() {
_storeAsDefault = !_storeAsDefault;

View file

@ -717,11 +717,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
? SizedBox(
height: 12,
width: 12,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
color: Theme.of(
context,
).colorScheme.inversePrimary,
valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.inversePrimary),
),
)
: const FaIcon(FontAwesomeIcons.solidPaperPlane),

View file

@ -172,7 +172,7 @@ class _DrawLayerState extends State<DrawLayer> {
Positioned.fill(
child: RotatedBox(
quarterTurns: 1,
child: Slider(
child: Slider.adaptive(
value: _sliderValue,
thumbColor: currentColor,
activeColor: Colors.transparent,

View file

@ -82,7 +82,7 @@ class TwitterPostCard extends StatelessWidget {
height: 150,
color: const Color(0xFFF5F8FA),
child: const Center(
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(twitterBlue),
),

View file

@ -190,7 +190,7 @@ class _ChatAskAFriendEntryState extends State<ChatAskAFriendEntry> {
child: SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
),
@ -302,7 +302,7 @@ class _ChatAskAFriendEntryState extends State<ChatAskAFriendEntry> {
? const SizedBox(
width: 12,
height: 12,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
)

View file

@ -191,7 +191,7 @@ class _ContactRowState extends State<_ContactRow> {
const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.white,

View file

@ -76,7 +76,7 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
SizedBox(
width: 10,
height: 10,
child: CircularProgressIndicator(strokeWidth: 1, color: color),
child: CircularProgressIndicator.adaptive(strokeWidth: 1, valueColor: AlwaysStoppedAnimation(color)),
),
const SizedBox(width: 2),
],

View file

@ -540,7 +540,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
const SizedBox(
width: 10,
height: 10,
child: CircularProgressIndicator(strokeWidth: 1),
child: CircularProgressIndicator.adaptive(strokeWidth: 1),
)
else
imageSaved

View file

@ -129,7 +129,7 @@ class _AddContactViaQrLinkViewState extends State<AddContactViaQrLinkView> {
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
)

View file

@ -250,7 +250,7 @@ class _SearchUsernameView extends State<AddNewUserView> {
child: SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
),
)
else

View file

@ -112,7 +112,7 @@ class FriendSuggestionsComp extends StatelessWidget {
final contact = f.$1;
final isSelected =
selectedFriends.contains(contact.userId);
return CheckboxListTile(
return CheckboxListTile.adaptive(
contentPadding: EdgeInsets.zero,
title: Text(contact.displayName ?? contact.username),
value: isSelected,

View file

@ -68,7 +68,7 @@ class _GroupCreateSelectGroupNameViewState
? const SizedBox(
width: 15,
height: 15,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 1,
),
)

View file

@ -223,7 +223,7 @@ class _StartNewChatView extends State<GroupCreateSelectMembersView> {
contactId: user.userId,
fontSize: 13,
),
trailing: Checkbox(
trailing: Checkbox.adaptive(
value:
selectedUsers.contains(user.userId) |
alreadyInGroup.contains(user.userId),

View file

@ -40,9 +40,9 @@ class SynchronizedViewerActionsToolbarComp extends StatelessWidget {
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
color: Colors.white,
valueColor: AlwaysStoppedAnimation(Colors.white),
),
)
: const FaIcon(

View file

@ -409,7 +409,9 @@ class MemoriesViewState extends State<MemoriesView> {
child: CircularProgressIndicator(
value: state.migrationProgress,
strokeWidth: 2.5,
color: context.color.primary,
valueColor: AlwaysStoppedAnimation(
context.color.primary,
),
backgroundColor: context.color.primary
.withValues(alpha: 0.2),
),

View file

@ -219,8 +219,8 @@ class _BackupRecoveryViewState extends State<BackupRecoveryView> {
? const SizedBox(
height: 24,
width: 24,
child: CircularProgressIndicator(
color: Colors.white,
child: CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation(Colors.white),
strokeWidth: 3,
),
)

View file

@ -299,8 +299,8 @@ class _RegisterViewState extends State<RegisterView> {
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
color: Colors.white,
child: CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation(Colors.white),
strokeWidth: 3,
),
)

View file

@ -49,7 +49,7 @@ class NextButtonComp extends StatelessWidget {
? const SizedBox(
height: 24,
width: 24,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),

View file

@ -28,7 +28,7 @@ class SetupSwitchCard extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SwitchListTile(
SwitchListTile.adaptive(
value: value,
onChanged: onChanged,
title: Text(

View file

@ -127,7 +127,7 @@ class _RecoveryViewState extends State<RecoveryView> {
? const SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(strokeWidth: 2),
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
)
: const Icon(Icons.restore_rounded),
style: FilledButton.styleFrom(

View file

@ -144,7 +144,7 @@ class _SetupBackupViewState extends State<SetupBackupView> {
? const SizedBox(
height: 12,
width: 12,
child: CircularProgressIndicator(strokeWidth: 1),
child: CircularProgressIndicator.adaptive(strokeWidth: 1),
)
: const Icon(Icons.lock_clock_rounded),
label: Text(

View file

@ -39,7 +39,7 @@ class _ChatSettingsViewState extends State<ChatSettingsView> {
title: Text(context.lang.settingsPreSelectedReactions),
onTap: () => context.push(Routes.settingsChatsReactions),
),
SwitchListTile(
SwitchListTile.adaptive(
title: Text(
context
.lang

View file

@ -213,7 +213,7 @@ class _AutoDownloadOptionsDialogState extends State<AutoDownloadOptionsDialog> {
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
CheckboxListTile(
CheckboxListTile.adaptive(
title: const Text('Image'),
value: autoDownloadOptions[widget.connectionMode.name]!.contains(
DownloadMediaTypes.image.name,
@ -222,7 +222,7 @@ class _AutoDownloadOptionsDialogState extends State<AutoDownloadOptionsDialog> {
await _updateAutoDownloadSetting(DownloadMediaTypes.image, value);
},
),
CheckboxListTile(
CheckboxListTile.adaptive(
title: const Text('Video'),
value: autoDownloadOptions[widget.connectionMode.name]!.contains(
DownloadMediaTypes.video.name,

View file

@ -379,7 +379,7 @@ class _ImportFromGalleryViewState extends State<ImportFromGalleryView> {
Widget _buildBody() {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
return const Center(child: CircularProgressIndicator.adaptive());
}
if (!_hasPermission) {
@ -530,7 +530,7 @@ class _ImportFromGalleryViewState extends State<ImportFromGalleryView> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const CircularProgressIndicator.adaptive(),
const SizedBox(height: 24),
Text(
_importStatus,
@ -600,7 +600,7 @@ class _GalleryThumbnailWidgetState extends State<GalleryThumbnailWidget> {
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
),
),
);

View file

@ -400,7 +400,7 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
)
: null,
onTap: _isGeneratingMockImages

View file

@ -112,7 +112,7 @@ class _ChangeLogViewState extends State<ChangeLogView> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(context.lang.openChangeLog),
Switch(
Switch.adaptive(
value: !userService.currentUser.hideChangeLog,
onChanged: (_) => UserService.update(
(u) => u.hideChangeLog = !u.hideChangeLog,

View file

@ -243,9 +243,9 @@ $debugLogToken
? SizedBox(
height: 12,
width: 12,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
color: Theme.of(context).colorScheme.inversePrimary,
valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.inversePrimary),
),
)
: const FaIcon(FontAwesomeIcons.angleRight),
@ -291,7 +291,7 @@ class _IncludeDebugLogState extends State<IncludeDebugLog> {
Widget build(BuildContext context) {
return Row(
children: [
Checkbox(
Checkbox.adaptive(
value: widget.isChecked,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: (value) {

View file

@ -117,7 +117,7 @@ class _FaqViewState extends State<FaqView> {
appBar: AppBar(
title: Text(context.lang.settingsHelpFAQ),
),
body: const Center(child: CircularProgressIndicator()),
body: const Center(child: CircularProgressIndicator.adaptive()),
);
}

View file

@ -123,7 +123,7 @@ class _NotificationViewState extends State<NotificationView> {
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
)
@ -138,7 +138,7 @@ class _NotificationViewState extends State<NotificationView> {
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
)

View file

@ -119,7 +119,7 @@ class UserList extends StatelessWidget {
],
),
leading: AvatarIcon(contactId: user.userId, fontSize: 15),
trailing: Checkbox(
trailing: Checkbox.adaptive(
value: user.blocked,
onChanged: (value) async {
await block(context, user.userId, value);

View file

@ -292,7 +292,7 @@ class UserDiscoverySetupComp extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SwitchListTile(
SwitchListTile.adaptive(
value: state.isUserDiscoveryEnabled,
onChanged: (val) => state.update(() {
state.isUserDiscoveryEnabled = val;
@ -323,7 +323,7 @@ class UserDiscoverySetupComp extends StatelessWidget {
),
),
),
SwitchListTile(
SwitchListTile.adaptive(
value: state.isManualApprovalEnabled,
onChanged: (val) => state.update(
() => state.isManualApprovalEnabled = val,
@ -547,7 +547,7 @@ class UserDiscoverySetupComp extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SwitchListTile(
SwitchListTile.adaptive(
value: state.sharePromotion,
onChanged: (val) => state.update(() {
state.sharePromotion = val;

View file

@ -195,7 +195,7 @@ class _SelectAdditionalUsers extends State<SelectAdditionalUsers> {
contactId: user.userId,
fontSize: 13,
),
trailing: Checkbox(
trailing: Checkbox.adaptive(
value:
selectedUsers.contains(user.userId) |
_alreadySelected.contains(user.userId),

View file

@ -330,7 +330,7 @@ class _PlanCardState extends State<PlanCard> {
? const SizedBox(
width: 10,
height: 10,
child: CircularProgressIndicator(strokeWidth: 1),
child: CircularProgressIndicator.adaptive(strokeWidth: 1),
)
: null,
label: Text(
@ -350,7 +350,7 @@ class _PlanCardState extends State<PlanCard> {
? const SizedBox(
width: 10,
height: 10,
child: CircularProgressIndicator(strokeWidth: 1),
child: CircularProgressIndicator.adaptive(strokeWidth: 1),
)
: null,
label: Text(

View file

@ -208,7 +208,7 @@ class _SelectAdditionalUsers extends State<SelectContactsView> {
contactId: user.userId,
fontSize: 13,
),
trailing: Checkbox(
trailing: Checkbox.adaptive(
value:
selectedUsers.contains(user.userId) |
_alreadySelected.contains(user.userId),

View file

@ -176,7 +176,7 @@ class _UserStudyQuestionnaireViewState
'Welche der folgenden Messenger hast du schon einmal benutzt?',
),
..._messengerOptions.map(
(m) => CheckboxListTile(
(m) => CheckboxListTile.adaptive(
title: Text(m),
visualDensity: const VisualDensity(vertical: -4),
value: (_responses['messengers'] as List<dynamic>).contains(m),