Merge branch 'krille/add-missing-safearea' into 'main'

fix: Add missing safearea

See merge request ChristianPauly/fluffychat-flutter!256
onboarding
Christian Pauly 5 years ago
commit 767559f838

@ -577,476 +577,486 @@ class _ChatState extends State<_Chat> {
width: double.infinity, width: double.infinity,
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
Column( SafeArea(
children: <Widget>[ child: Column(
ConnectionStatusHeader(), children: <Widget>[
Expanded( ConnectionStatusHeader(),
child: FutureBuilder<bool>( Expanded(
future: getTimeline(context), child: FutureBuilder<bool>(
builder: (BuildContext context, snapshot) { future: getTimeline(context),
if (!snapshot.hasData) { builder: (BuildContext context, snapshot) {
return Center( if (!snapshot.hasData) {
child: CircularProgressIndicator(), return Center(
); child: CircularProgressIndicator(),
} );
}
if (room.notificationCount != null &&
room.notificationCount > 0 && if (room.notificationCount != null &&
timeline != null && room.notificationCount > 0 &&
timeline.events.isNotEmpty && timeline != null &&
Matrix.of(context).webHasFocus) { timeline.events.isNotEmpty &&
room.sendReadReceipt(timeline.events.first.eventId); Matrix.of(context).webHasFocus) {
} room.sendReadReceipt(timeline.events.first.eventId);
}
final filteredEvents = getFilteredEvents();
final filteredEvents = getFilteredEvents();
return ListView.builder(
padding: EdgeInsets.symmetric( return ListView.builder(
horizontal: max( padding: EdgeInsets.symmetric(
0, horizontal: max(
(MediaQuery.of(context).size.width - 0,
AdaptivePageLayout.defaultMinWidth * (MediaQuery.of(context).size.width -
3.5) / AdaptivePageLayout.defaultMinWidth *
2), 3.5) /
), 2),
reverse: true, ),
itemCount: filteredEvents.length + 2, reverse: true,
controller: _scrollController, itemCount: filteredEvents.length + 2,
itemBuilder: (BuildContext context, int i) { controller: _scrollController,
return i == filteredEvents.length + 1 itemBuilder: (BuildContext context, int i) {
? _loadingHistory return i == filteredEvents.length + 1
? Container( ? _loadingHistory
height: 50, ? Container(
alignment: Alignment.center, height: 50,
padding: EdgeInsets.all(8), alignment: Alignment.center,
child: CircularProgressIndicator(), padding: EdgeInsets.all(8),
) child: CircularProgressIndicator(),
: _canLoadMore )
? FlatButton( : _canLoadMore
? FlatButton(
child: Text(
L10n.of(context).loadMore,
style: TextStyle(
color: Theme.of(context)
.primaryColor,
fontWeight: FontWeight.bold,
decoration:
TextDecoration.underline,
),
),
onPressed: requestHistory,
)
: Container()
: i == 0
? AnimatedContainer(
height: seenByText.isEmpty ? 0 : 24,
duration: seenByText.isEmpty
? Duration(milliseconds: 0)
: Duration(milliseconds: 300),
alignment:
filteredEvents.first.senderId ==
client.userID
? Alignment.topRight
: Alignment.topLeft,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 4),
decoration: BoxDecoration(
color: Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.8),
borderRadius:
BorderRadius.circular(4),
),
child: Text( child: Text(
L10n.of(context).loadMore, seenByText,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.primaryColor, .primaryColor,
fontWeight: FontWeight.bold,
decoration:
TextDecoration.underline,
), ),
), ),
onPressed: requestHistory,
)
: Container()
: i == 0
? AnimatedContainer(
height: seenByText.isEmpty ? 0 : 24,
duration: seenByText.isEmpty
? Duration(milliseconds: 0)
: Duration(milliseconds: 300),
alignment:
filteredEvents.first.senderId ==
client.userID
? Alignment.topRight
: Alignment.topLeft,
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.8),
borderRadius:
BorderRadius.circular(4),
), ),
child: Text( padding: EdgeInsets.only(
seenByText, left: 8,
maxLines: 1, right: 8,
overflow: TextOverflow.ellipsis, bottom: 8,
style: TextStyle(
color:
Theme.of(context).primaryColor,
),
), ),
), )
padding: EdgeInsets.only( : AutoScrollTag(
left: 8, key: ValueKey(i - 1),
right: 8, index: i - 1,
bottom: 8, controller: _scrollController,
), child: Swipeable(
) key: ValueKey(
: AutoScrollTag( filteredEvents[i - 1].eventId),
key: ValueKey(i - 1), background: Padding(
index: i - 1, padding: EdgeInsets.symmetric(
controller: _scrollController, horizontal: 12.0),
child: Swipeable( child: Center(
key: ValueKey( child: Icon(Icons.reply),
filteredEvents[i - 1].eventId), ),
background: Padding(
padding: EdgeInsets.symmetric(
horizontal: 12.0),
child: Center(
child: Icon(Icons.reply),
), ),
), direction: SwipeDirection.endToStart,
direction: SwipeDirection.endToStart, onSwipe: (direction) => replyAction(
onSwipe: (direction) => replyAction( replyTo: filteredEvents[i - 1]),
replyTo: filteredEvents[i - 1]), child: Message(filteredEvents[i - 1],
child: Message(filteredEvents[i - 1], onAvatarTab: (Event event) =>
onAvatarTab: (Event event) => showModalBottomSheet(
showModalBottomSheet( context: context,
context: context, builder: (context) =>
builder: (context) => UserBottomSheet(
UserBottomSheet( user: event.sender,
user: event.sender, onMention: () =>
onMention: () => sendController.text +=
sendController.text += ' ${event.senderId}',
' ${event.senderId}', ),
), ),
), onSelect: (Event event) {
onSelect: (Event event) { if (!event.redacted) {
if (!event.redacted) { if (selectedEvents
if (selectedEvents .contains(event)) {
.contains(event)) { setState(
setState( () => selectedEvents
() => selectedEvents .remove(event),
.remove(event), );
); } else {
} else { setState(
setState( () => selectedEvents
() => selectedEvents .add(event),
.add(event), );
}
selectedEvents.sort(
(a, b) => a.originServerTs
.compareTo(
b.originServerTs),
); );
} }
selectedEvents.sort( },
(a, b) => a.originServerTs scrollToEventId:
.compareTo( (String eventId) =>
b.originServerTs), _scrollToEventId(eventId,
); context: context),
} longPressSelect:
}, selectedEvents.isEmpty,
scrollToEventId: (String eventId) => selected: selectedEvents.contains(
_scrollToEventId(eventId, filteredEvents[i - 1]),
context: context), timeline: timeline,
longPressSelect: nextEvent: i >= 2
selectedEvents.isEmpty, ? filteredEvents[i - 2]
selected: selectedEvents.contains( : null),
filteredEvents[i - 1]), ),
timeline: timeline, );
nextEvent: i >= 2 });
? filteredEvents[i - 2] },
: null), ),
),
);
});
},
), ),
), AnimatedContainer(
AnimatedContainer( duration: Duration(milliseconds: 300),
duration: Duration(milliseconds: 300), height: (editEvent == null &&
height: (editEvent == null && replyEvent == null &&
replyEvent == null && selectedEvents.length == 1)
selectedEvents.length == 1) ? 56
? 56 : 0,
: 0, child: Material(
child: Material( color: Theme.of(context).secondaryHeaderColor,
color: Theme.of(context).secondaryHeaderColor, child: Builder(builder: (context) {
child: Builder(builder: (context) { if (!(editEvent == null &&
if (!(editEvent == null && replyEvent == null &&
replyEvent == null && selectedEvents.length == 1)) {
selectedEvents.length == 1)) { return Container();
return Container(); }
} var emojis = List<String>.from(AppEmojis.emojis);
var emojis = List<String>.from(AppEmojis.emojis); final allReactionEvents = selectedEvents.first
final allReactionEvents = selectedEvents.first .aggregatedEvents(
.aggregatedEvents(timeline, RelationshipTypes.Reaction) timeline, RelationshipTypes.Reaction)
?.where((event) => ?.where((event) =>
event.senderId == event.room.client.userID && event.senderId == event.room.client.userID &&
event.type == 'm.reaction'); event.type == 'm.reaction');
allReactionEvents.forEach((event) { allReactionEvents.forEach((event) {
try { try {
emojis.remove(event.content['m.relates_to']['key']); emojis.remove(event.content['m.relates_to']['key']);
} catch (_) {} } catch (_) {}
}); });
return ListView.builder( return ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: emojis.length, itemCount: emojis.length,
itemBuilder: (c, i) => InkWell( itemBuilder: (c, i) => InkWell(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
onTap: () { onTap: () {
SimpleDialogs(context).tryRequestWithLoadingDialog( SimpleDialogs(context).tryRequestWithLoadingDialog(
room.sendReaction( room.sendReaction(
selectedEvents.first.eventId, selectedEvents.first.eventId,
emojis[i],
),
);
setState(() => selectedEvents.clear());
},
child: Container(
width: 56,
height: 56,
alignment: Alignment.center,
child: Text(
emojis[i], emojis[i],
style: TextStyle(fontSize: 30),
), ),
);
setState(() => selectedEvents.clear());
},
child: Container(
width: 56,
height: 56,
alignment: Alignment.center,
child: Text(
emojis[i],
style: TextStyle(fontSize: 30),
), ),
), ),
), );
); }),
}), ),
), ),
), AnimatedContainer(
AnimatedContainer( duration: Duration(milliseconds: 300),
duration: Duration(milliseconds: 300), height: editEvent != null || replyEvent != null ? 56 : 0,
height: editEvent != null || replyEvent != null ? 56 : 0, child: Material(
child: Material( color: Theme.of(context).secondaryHeaderColor,
color: Theme.of(context).secondaryHeaderColor, child: Row(
child: Row( children: <Widget>[
children: <Widget>[ IconButton(
IconButton( icon: Icon(Icons.close),
icon: Icon(Icons.close), onPressed: () => setState(() {
onPressed: () => setState(() { if (editEvent != null) {
if (editEvent != null) { inputText = sendController.text = pendingText;
inputText = sendController.text = pendingText; pendingText = '';
pendingText = ''; }
} replyEvent = null;
replyEvent = null; editEvent = null;
editEvent = null; }),
}), ),
), Expanded(
Expanded( child: replyEvent != null
child: replyEvent != null ? ReplyContent(replyEvent, timeline: timeline)
? ReplyContent(replyEvent, timeline: timeline) : _EditContent(
: _EditContent( editEvent?.getDisplayEvent(timeline)),
editEvent?.getDisplayEvent(timeline)), ),
), ],
], ),
), ),
), ),
), Divider(
Divider( height: 1,
height: 1, color: Theme.of(context).secondaryHeaderColor,
color: Theme.of(context).secondaryHeaderColor, thickness: 1,
thickness: 1, ),
), room.canSendDefaultMessages &&
room.canSendDefaultMessages && room.membership == Membership.join room.membership == Membership.join
? Container( ? Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).backgroundColor, color: Theme.of(context).backgroundColor,
), ),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: selectMode children: selectMode
? <Widget>[ ? <Widget>[
Container( Container(
height: 56, height: 56,
child: FlatButton( child: FlatButton(
onPressed: () => onPressed: () =>
forwardEventsAction(context), forwardEventsAction(context),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.keyboard_arrow_left), Icon(Icons.keyboard_arrow_left),
Text(L10n.of(context).forward), Text(L10n.of(context).forward),
], ],
),
), ),
), ),
), selectedEvents.length == 1
selectedEvents.length == 1 ? selectedEvents.first
? selectedEvents.first .getDisplayEvent(timeline)
.getDisplayEvent(timeline) .status >
.status > 0
0 ? Container(
? Container( height: 56,
height: 56, child: FlatButton(
child: FlatButton( onPressed: () => replyAction(),
onPressed: () => replyAction(), child: Row(
child: Row( children: <Widget>[
children: <Widget>[ Text(
Text(L10n.of(context).reply), L10n.of(context).reply),
Icon(Icons Icon(Icons
.keyboard_arrow_right), .keyboard_arrow_right),
], ],
),
), ),
), )
) : Container(
: Container( height: 56,
height: 56, child: FlatButton(
child: FlatButton( onPressed: () =>
onPressed: () => sendAgainAction(timeline),
sendAgainAction(timeline), child: Row(
child: Row( children: <Widget>[
children: <Widget>[ Text(L10n.of(context)
Text(L10n.of(context) .tryToSendAgain),
.tryToSendAgain), SizedBox(width: 4),
SizedBox(width: 4), Icon(Icons.send, size: 16),
Icon(Icons.send, size: 16), ],
], ),
), ),
), )
) : Container(),
: Container(), ]
] : <Widget>[
: <Widget>[ if (inputText.isEmpty)
if (inputText.isEmpty) Container(
Container( height: 56,
height: 56, alignment: Alignment.center,
alignment: Alignment.center, child: PopupMenuButton<String>(
child: PopupMenuButton<String>( icon: Icon(Icons.add),
icon: Icon(Icons.add), onSelected: (String choice) async {
onSelected: (String choice) async { if (choice == 'file') {
if (choice == 'file') { sendFileAction(context);
sendFileAction(context); } else if (choice == 'image') {
} else if (choice == 'image') { sendImageAction(context);
sendImageAction(context); }
} if (choice == 'camera') {
if (choice == 'camera') { openCameraAction(context);
openCameraAction(context); }
} if (choice == 'voice') {
if (choice == 'voice') { voiceMessageAction(context);
voiceMessageAction(context); }
} },
}, itemBuilder: (BuildContext context) =>
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
<PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'file',
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
child: Icon(Icons.attachment),
),
title:
Text(L10n.of(context).sendFile),
contentPadding: EdgeInsets.all(0),
),
),
PopupMenuItem<String>(
value: 'image',
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
child: Icon(Icons.image),
),
title: Text(
L10n.of(context).sendImage),
contentPadding: EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>( PopupMenuItem<String>(
value: 'camera', value: 'file',
child: ListTile( child: ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: Colors.purple, backgroundColor: Colors.green,
foregroundColor: Colors.white, foregroundColor: Colors.white,
child: Icon(Icons.camera_alt), child: Icon(Icons.attachment),
), ),
title: Text( title: Text(
L10n.of(context).openCamera), L10n.of(context).sendFile),
contentPadding: EdgeInsets.all(0), contentPadding: EdgeInsets.all(0),
), ),
), ),
if (PlatformInfos.isMobile)
PopupMenuItem<String>( PopupMenuItem<String>(
value: 'voice', value: 'image',
child: ListTile( child: ListTile(
leading: CircleAvatar( leading: CircleAvatar(
backgroundColor: Colors.red, backgroundColor: Colors.blue,
foregroundColor: Colors.white, foregroundColor: Colors.white,
child: Icon(Icons.mic), child: Icon(Icons.image),
), ),
title: Text(L10n.of(context) title: Text(
.voiceMessage), L10n.of(context).sendImage),
contentPadding: EdgeInsets.all(0), contentPadding: EdgeInsets.all(0),
), ),
), ),
], if (PlatformInfos.isMobile)
), PopupMenuItem<String>(
), value: 'camera',
Container( child: ListTile(
height: 56, leading: CircleAvatar(
alignment: Alignment.center, backgroundColor:
child: EncryptionButton(room), Colors.purple,
), foregroundColor: Colors.white,
Expanded( child: Icon(Icons.camera_alt),
child: Padding( ),
padding: const EdgeInsets.symmetric( title: Text(L10n.of(context)
vertical: 4.0), .openCamera),
child: InputBar( contentPadding:
room: room, EdgeInsets.all(0),
minLines: 1, ),
maxLines: kIsWeb ? 1 : 8, ),
autofocus: !PlatformInfos.isMobile, if (PlatformInfos.isMobile)
keyboardType: !PlatformInfos.isMobile PopupMenuItem<String>(
? TextInputType.text value: 'voice',
: TextInputType.multiline, child: ListTile(
onSubmitted: (String text) { leading: CircleAvatar(
send(); backgroundColor: Colors.red,
FocusScope.of(context) foregroundColor: Colors.white,
.requestFocus(inputFocus); child: Icon(Icons.mic),
}, ),
focusNode: inputFocus, title: Text(L10n.of(context)
controller: sendController, .voiceMessage),
decoration: InputDecoration( contentPadding:
hintText: EdgeInsets.all(0),
L10n.of(context).writeAMessage, ),
hintMaxLines: 1, ),
border: InputBorder.none, ],
), ),
onChanged: (String text) {
typingCoolDown?.cancel();
typingCoolDown =
Timer(Duration(seconds: 2), () {
typingCoolDown = null;
currentlyTyping = false;
room.sendTypingInfo(false);
});
typingTimeout ??=
Timer(Duration(seconds: 30), () {
typingTimeout = null;
currentlyTyping = false;
});
if (!currentlyTyping) {
currentlyTyping = true;
room.sendTypingInfo(true,
timeout: Duration(seconds: 30)
.inMilliseconds);
}
// Workaround for a current desktop bug
if (!PlatformInfos.isBetaDesktop) {
setState(() => inputText = text);
}
},
), ),
),
),
if (PlatformInfos.isMobile && inputText.isEmpty)
Container( Container(
height: 56, height: 56,
alignment: Alignment.center, alignment: Alignment.center,
child: IconButton( child: EncryptionButton(room),
icon: Icon(Icons.mic),
onPressed: () =>
voiceMessageAction(context),
),
), ),
if (!PlatformInfos.isMobile || Expanded(
inputText.isNotEmpty) child: Padding(
Container( padding: const EdgeInsets.symmetric(
height: 56, vertical: 4.0),
alignment: Alignment.center, child: InputBar(
child: IconButton( room: room,
icon: Icon(Icons.send), minLines: 1,
onPressed: () => send(), maxLines: kIsWeb ? 1 : 8,
autofocus: !PlatformInfos.isMobile,
keyboardType: !PlatformInfos.isMobile
? TextInputType.text
: TextInputType.multiline,
onSubmitted: (String text) {
send();
FocusScope.of(context)
.requestFocus(inputFocus);
},
focusNode: inputFocus,
controller: sendController,
decoration: InputDecoration(
hintText:
L10n.of(context).writeAMessage,
hintMaxLines: 1,
border: InputBorder.none,
),
onChanged: (String text) {
typingCoolDown?.cancel();
typingCoolDown =
Timer(Duration(seconds: 2), () {
typingCoolDown = null;
currentlyTyping = false;
room.sendTypingInfo(false);
});
typingTimeout ??=
Timer(Duration(seconds: 30), () {
typingTimeout = null;
currentlyTyping = false;
});
if (!currentlyTyping) {
currentlyTyping = true;
room.sendTypingInfo(true,
timeout: Duration(seconds: 30)
.inMilliseconds);
}
// Workaround for a current desktop bug
if (!PlatformInfos.isBetaDesktop) {
setState(() => inputText = text);
}
},
),
), ),
), ),
], if (PlatformInfos.isMobile &&
), inputText.isEmpty)
) Container(
: Container(), height: 56,
], alignment: Alignment.center,
child: IconButton(
icon: Icon(Icons.mic),
onPressed: () =>
voiceMessageAction(context),
),
),
if (!PlatformInfos.isMobile ||
inputText.isNotEmpty)
Container(
height: 56,
alignment: Alignment.center,
child: IconButton(
icon: Icon(Icons.send),
onPressed: () => send(),
),
),
],
),
)
: Container(),
],
),
), ),
], ],
), ),

Loading…
Cancel
Save