design: Column mode auto padding

This commit is contained in:
Christian Pauly 2021-04-09 18:26:44 +02:00
parent 0146767e8a
commit 75258271af
13 changed files with 1344 additions and 1239 deletions

View File

@ -10,6 +10,7 @@ import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:fluffychat/views/widgets/chat_settings_popup_menu.dart';
import 'package:fluffychat/views/widgets/content_banner.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/views/widgets/list_items/participant_list_item.dart';
import 'package:fluffychat/utils/matrix_locals.dart';
@ -234,8 +235,10 @@ class _ChatDetailsState extends State<ChatDetails> {
),
),
],
body: ListView.builder(
itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0),
body: MaxWidthBody(
child: ListView.builder(
itemCount:
members.length + 1 + (canRequestMoreMembers ? 1 : 0),
itemBuilder: (BuildContext context, int i) => i == 0
? Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
@ -250,7 +253,8 @@ class _ChatDetailsState extends State<ChatDetails> {
child: Icon(Icons.edit_outlined),
)
: null,
title: Text('${L10n.of(context).groupDescription}:',
title: Text(
'${L10n.of(context).groupDescription}:',
style: TextStyle(
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold)),
@ -261,8 +265,10 @@ class _ChatDetailsState extends State<ChatDetails> {
linkStyle: TextStyle(color: Colors.blueAccent),
textStyle: TextStyle(
fontSize: 14,
color:
Theme.of(context).textTheme.bodyText2.color,
color: Theme.of(context)
.textTheme
.bodyText2
.color,
),
onLinkTap: (url) =>
UrlLauncher(context, url).launchUrl(),
@ -331,8 +337,8 @@ class _ChatDetailsState extends State<ChatDetails> {
await AdaptivePageLayout.of(context)
.pushNamed('/rooms/${room.id}/emotes');
} else {
await AdaptivePageLayout.of(context).pushNamed(
'/settings/emotes',
await AdaptivePageLayout.of(context)
.pushNamed('/settings/emotes',
arguments: {'room': room});
}
},
@ -362,12 +368,12 @@ class _ChatDetailsState extends State<ChatDetails> {
],
child: ListTile(
leading: CircleAvatar(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
backgroundColor: Theme.of(context)
.scaffoldBackgroundColor,
foregroundColor: Colors.grey,
child: Icon(Icons.public_outlined)),
title: Text(
L10n.of(context).whoIsAllowedToJoinThisGroup),
title: Text(L10n.of(context)
.whoIsAllowedToJoinThisGroup),
subtitle: Text(
room.joinRules.getLocalizedString(
MatrixLocals(L10n.of(context))),
@ -375,11 +381,12 @@ class _ChatDetailsState extends State<ChatDetails> {
),
),
PopupMenuButton(
onSelected: (HistoryVisibility historyVisibility) =>
onSelected:
(HistoryVisibility historyVisibility) =>
showFutureLoadingDialog(
context: context,
future: () =>
room.setHistoryVisibility(historyVisibility),
future: () => room
.setHistoryVisibility(historyVisibility),
),
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<HistoryVisibility>>[
@ -419,8 +426,8 @@ class _ChatDetailsState extends State<ChatDetails> {
foregroundColor: Colors.grey,
child: Icon(Icons.visibility_outlined),
),
title: Text(
L10n.of(context).visibilityOfTheChatHistory),
title: Text(L10n.of(context)
.visibilityOfTheChatHistory),
subtitle: Text(
room.historyVisibility.getLocalizedString(
MatrixLocals(L10n.of(context))),
@ -432,7 +439,8 @@ class _ChatDetailsState extends State<ChatDetails> {
onSelected: (GuestAccess guestAccess) =>
showFutureLoadingDialog(
context: context,
future: () => room.setGuestAccess(guestAccess),
future: () =>
room.setGuestAccess(guestAccess),
),
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<GuestAccess>>[
@ -448,15 +456,16 @@ class _ChatDetailsState extends State<ChatDetails> {
PopupMenuItem<GuestAccess>(
value: GuestAccess.forbidden,
child: Text(
GuestAccess.forbidden.getLocalizedString(
GuestAccess.forbidden
.getLocalizedString(
MatrixLocals(L10n.of(context))),
),
),
],
child: ListTile(
leading: CircleAvatar(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
backgroundColor: Theme.of(context)
.scaffoldBackgroundColor,
foregroundColor: Colors.grey,
child: Icon(Icons.info_outline),
),
@ -470,8 +479,8 @@ class _ChatDetailsState extends State<ChatDetails> {
),
ListTile(
title: Text(L10n.of(context).editChatPermissions),
subtitle:
Text(L10n.of(context).whoCanPerformWhichAction),
subtitle: Text(
L10n.of(context).whoCanPerformWhichAction),
leading: CircleAvatar(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
@ -529,6 +538,7 @@ class _ChatDetailsState extends State<ChatDetails> {
),
),
),
),
);
});
}

View File

@ -2,6 +2,7 @@ import 'package:famedlysdk/encryption.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/avatar.dart';
import 'package:fluffychat/views/widgets/matrix.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../views/widgets/dialogs/key_verification_dialog.dart';
@ -81,7 +82,9 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
),
),
),
body: StreamBuilder(
body: MaxWidthBody(
withScrolling: true,
child: StreamBuilder(
stream: room.onUpdate.stream,
builder: (context, snapshot) {
return FutureBuilder<List<DeviceKeys>>(
@ -99,19 +102,24 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
}
final deviceKeys = snapshot.data;
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: deviceKeys.length,
itemBuilder: (BuildContext context, int i) => Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (i == 0 ||
deviceKeys[i].userId != deviceKeys[i - 1].userId) ...{
deviceKeys[i].userId !=
deviceKeys[i - 1].userId) ...{
Divider(height: 1, thickness: 1),
PopupMenuButton(
onSelected: (action) =>
onSelected(context, action, deviceKeys[i]),
itemBuilder: (c) {
var items = <PopupMenuEntry<String>>[];
if (room.client.userDeviceKeys[deviceKeys[i].userId]
if (room
.client
.userDeviceKeys[deviceKeys[i].userId]
.verified ==
UserVerifiedStatus.unknown) {
items.add(PopupMenuItem(
@ -162,7 +170,8 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
if (deviceKeys[i].blocked ||
!deviceKeys[i].verified) {
items.add(PopupMenuItem(
value: deviceKeys[i].userId == room.client.userID
value:
deviceKeys[i].userId == room.client.userID
? 'verify'
: 'verify_user',
child: Text(L10n.of(context).verifyStart),
@ -234,6 +243,7 @@ class _ChatEncryptionSettingsState extends State<ChatEncryptionSettings> {
},
);
}),
),
);
}
}

View File

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:fluffychat/views/widgets/dialogs/permission_slider_dialog.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/views/widgets/matrix.dart';
@ -52,12 +53,14 @@ class ChatPermissionsSettings extends StatelessWidget {
leading: BackButton(),
title: Text(L10n.of(context).editChatPermissions),
),
body: StreamBuilder(
body: MaxWidthBody(
withScrolling: true,
child: StreamBuilder(
stream: Matrix.of(context).client.onSync.stream.where(
(e) =>
(e?.rooms?.join?.containsKey(roomId) ?? false) &&
(e.rooms.join[roomId]?.timeline?.events
?.any((s) => s.type == EventTypes.RoomPowerLevels) ??
(e.rooms.join[roomId]?.timeline?.events?.any(
(s) => s.type == EventTypes.RoomPowerLevels) ??
false),
),
builder: (context, _) {
@ -70,7 +73,7 @@ class ChatPermissionsSettings extends StatelessWidget {
Map<String, dynamic>.from(powerLevelsContent['events'])
..removeWhere((k, v) => !(v is int));
return ListView(
return Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
@ -94,8 +97,8 @@ class ChatPermissionsSettings extends StatelessWidget {
),
Builder(builder: (context) {
final key = 'rooms';
final int value =
powerLevelsContent.containsKey('notifications')
final int value = powerLevelsContent
.containsKey('notifications')
? powerLevelsContent['notifications']['rooms'] ?? 0
: 0;
return PermissionsListTile(
@ -168,7 +171,8 @@ class ChatPermissionsSettings extends StatelessWidget {
context: context,
future: () =>
room.client.upgradeRoom(roomId, newVersion),
).then((_) => AdaptivePageLayout.of(context).pop());
).then(
(_) => AdaptivePageLayout.of(context).pop());
},
);
},
@ -180,6 +184,7 @@ class ChatPermissionsSettings extends StatelessWidget {
);
},
),
),
);
}
}

View File

@ -5,6 +5,7 @@ import 'package:fluffychat/views/widgets/default_app_bar_search_field.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/avatar.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/views/widgets/matrix.dart';
import 'package:flutter/material.dart';
@ -128,8 +129,12 @@ class _InvitationSelectionState extends State<InvitationSelection> {
onChanged: (String text) => searchUserWithCoolDown(context, text),
),
),
body: foundProfiles.isNotEmpty
body: MaxWidthBody(
withScrolling: true,
child: foundProfiles.isNotEmpty
? ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: foundProfiles.length,
itemBuilder: (BuildContext context, int i) => ListTile(
leading: Avatar(
@ -154,6 +159,8 @@ class _InvitationSelectionState extends State<InvitationSelection> {
}
var contacts = snapshot.data;
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: contacts.length,
itemBuilder: (BuildContext context, int i) => ListTile(
leading: Avatar(
@ -167,6 +174,7 @@ class _InvitationSelectionState extends State<InvitationSelection> {
);
},
),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart' as sdk;
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/views/widgets/matrix.dart';
import 'package:flutter/material.dart';
@ -45,7 +46,8 @@ class _NewGroupState extends State<NewGroup> {
title: Text(L10n.of(context).createNewGroup),
elevation: 0,
),
body: Column(
body: MaxWidthBody(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
@ -72,6 +74,7 @@ class _NewGroupState extends State<NewGroup> {
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => submitAction(context),
child: Icon(Icons.arrow_forward_outlined),

View File

@ -4,6 +4,7 @@ import 'package:adaptive_page_layout/adaptive_page_layout.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/avatar.dart';
import 'package:fluffychat/views/widgets/contacts_list.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/views/widgets/matrix.dart';
import 'package:fluffychat/utils/fluffy_share.dart';
@ -101,7 +102,8 @@ class _NewPrivateChatState extends State<NewPrivateChat> {
)
],
),
body: Column(
body: MaxWidthBody(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
@ -145,7 +147,8 @@ class _NewPrivateChatState extends State<NewPrivateChat> {
padding: const EdgeInsets.all(8.0),
child: Avatar(
foundProfile.avatarUrl,
foundProfile.displayname ?? foundProfile.userId,
foundProfile.displayname ??
foundProfile.userId,
size: 12,
),
)
@ -198,7 +201,8 @@ class _NewPrivateChatState extends State<NewPrivateChat> {
//size: 24,
),
title: Text(
foundProfile.displayname ?? foundProfile.userId.localpart,
foundProfile.displayname ??
foundProfile.userId.localpart,
style: TextStyle(),
maxLines: 1,
),
@ -219,6 +223,7 @@ class _NewPrivateChatState extends State<NewPrivateChat> {
),
],
),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/views/widgets/matrix.dart';
import 'package:flutter/material.dart';
@ -99,7 +100,8 @@ class _Settings3PidState extends State<Settings3Pid> {
)
],
),
body: FutureBuilder<List<ThirdPartyIdentifier>>(
body: MaxWidthBody(
child: FutureBuilder<List<ThirdPartyIdentifier>>(
future: _request,
builder: (BuildContext context,
AsyncSnapshot<List<ThirdPartyIdentifier>> snapshot) {
@ -131,7 +133,8 @@ class _Settings3PidState extends State<Settings3Pid> {
title: Text(
identifier.isEmpty
? L10n.of(context).noPasswordRecoveryDescription
: L10n.of(context).withTheseAddressesRecoveryDescription,
: L10n.of(context)
.withTheseAddressesRecoveryDescription,
),
),
Divider(height: 1),
@ -158,6 +161,7 @@ class _Settings3PidState extends State<Settings3Pid> {
);
},
),
),
);
}
}

View File

@ -2,6 +2,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:famedlysdk/encryption/utils/key_verification.dart';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/dialogs/key_verification_dialog.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -131,7 +132,8 @@ class DevicesSettingsState extends State<DevicesSettings> {
leading: BackButton(),
title: Text(L10n.of(context).devices),
),
body: FutureBuilder<bool>(
body: MaxWidthBody(
child: FutureBuilder<bool>(
future: _loadUserDevices(context),
builder: (BuildContext context, snapshot) {
if (snapshot.hasError) {
@ -151,7 +153,8 @@ class DevicesSettingsState extends State<DevicesSettings> {
Function isOwnDevice = (Device userDevice) =>
userDevice.deviceId == Matrix.of(context).client.deviceID;
final devices = List<Device>.from(this.devices);
var thisDevice = devices.firstWhere(isOwnDevice, orElse: () => null);
var thisDevice =
devices.firstWhere(isOwnDevice, orElse: () => null);
devices.removeWhere(isOwnDevice);
devices.sort((a, b) => b.lastSeenTs.compareTo(a.lastSeenTs));
return Column(
@ -209,6 +212,7 @@ class DevicesSettingsState extends State<DevicesSettings> {
);
},
),
),
);
}
}

View File

@ -6,6 +6,7 @@ import 'package:famedlysdk/famedlysdk.dart';
import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -184,7 +185,8 @@ class _EmotesSettingsState extends State<EmotesSettings> {
child: Icon(Icons.save_outlined, color: Colors.white),
)
: null,
body: StreamBuilder(
body: MaxWidthBody(
child: StreamBuilder(
stream: widget.room?.onUpdate?.stream,
builder: (context, snapshot) {
return Column(
@ -324,7 +326,8 @@ class _EmotesSettingsState extends State<EmotesSettings> {
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(10)),
color: Theme.of(context).secondaryHeaderColor,
color:
Theme.of(context).secondaryHeaderColor,
),
child: TextField(
readOnly: readonly,
@ -366,7 +369,8 @@ class _EmotesSettingsState extends State<EmotesSettings> {
controller.text = emote.emoteClean;
showOkAlertDialog(
context: context,
message: L10n.of(context).emoteInvalid,
message:
L10n.of(context).emoteInvalid,
okLabel: L10n.of(context).ok,
useRootNavigator: false,
);
@ -401,6 +405,7 @@ class _EmotesSettingsState extends State<EmotesSettings> {
],
);
}),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/avatar.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -45,7 +46,8 @@ class _SettingsIgnoreListState extends State<SettingsIgnoreList> {
leading: BackButton(),
title: Text(L10n.of(context).ignoredUsers),
),
body: Column(
body: MaxWidthBody(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
@ -93,8 +95,8 @@ class _SettingsIgnoreListState extends State<SettingsIgnoreList> {
s.data?.avatarUrl ?? Uri.parse(''),
s.data?.displayname ?? client.ignoredUsers[i],
),
title:
Text(s.data?.displayname ?? client.ignoredUsers[i]),
title: Text(
s.data?.displayname ?? client.ignoredUsers[i]),
trailing: IconButton(
tooltip: L10n.of(context).delete,
icon: Icon(Icons.delete_forever_outlined),
@ -111,6 +113,7 @@ class _SettingsIgnoreListState extends State<SettingsIgnoreList> {
),
],
),
),
);
}
}

View File

@ -1,6 +1,7 @@
import 'dart:io';
import 'package:famedlysdk/famedlysdk.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:flutter/foundation.dart';
@ -113,25 +114,28 @@ class SettingsNotifications extends StatelessWidget {
leading: BackButton(),
title: Text(L10n.of(context).notifications),
),
body: StreamBuilder(
body: MaxWidthBody(
withScrolling: true,
child: StreamBuilder(
stream: Matrix.of(context)
.client
.onAccountData
.stream
.where((event) => event.type == 'm.push_rules'),
builder: (BuildContext context, _) {
return ListView(
return Column(
children: [
SwitchListTile(
value: !Matrix.of(context).client.allPushNotificationsMuted,
title:
Text(L10n.of(context).notificationsEnabledForThisAccount),
title: Text(
L10n.of(context).notificationsEnabledForThisAccount),
onChanged: (_) => showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context)
future: () =>
Matrix.of(context).client.setMuteAllPushNotifications(
!Matrix.of(context)
.client
.setMuteAllPushNotifications(
!Matrix.of(context).client.allPushNotificationsMuted,
.allPushNotificationsMuted,
),
),
),
@ -204,6 +208,7 @@ class SettingsNotifications extends StatelessWidget {
],
);
}),
),
);
}
}

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/views/widgets/max_width_body.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:image_picker/image_picker.dart';
@ -56,7 +57,9 @@ class _SettingsStyleState extends State<SettingsStyle> {
leading: BackButton(),
title: Text(L10n.of(context).changeTheme),
),
body: ListView(
body: MaxWidthBody(
withScrolling: true,
child: Column(
children: [
RadioListTile<AdaptiveThemeMode>(
groupValue: _currentTheme,
@ -121,7 +124,8 @@ class _SettingsStyleState extends State<SettingsStyle> {
alignment: Alignment.centerLeft,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
padding:
const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
decoration: BoxDecoration(
color: Theme.of(context).secondaryHeaderColor,
borderRadius: BorderRadius.circular(16),
@ -151,6 +155,7 @@ class _SettingsStyleState extends State<SettingsStyle> {
),
],
),
),
);
}
}

View File

@ -0,0 +1,38 @@
import 'dart:math';
import 'package:flutter/material.dart';
class MaxWidthBody extends StatelessWidget {
final Widget child;
final double maxWidth;
final bool withScrolling;
const MaxWidthBody({
this.child,
this.maxWidth = 600,
this.withScrolling = false,
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final padding = EdgeInsets.symmetric(
horizontal: max(0, (constraints.maxWidth - maxWidth) / 2),
);
return withScrolling
? SingleChildScrollView(
physics: ScrollPhysics(),
child: Padding(
padding: padding,
child: child,
),
)
: Padding(
padding: padding,
child: child,
);
},
);
}
}