chore: Add replies and hold to show

This commit is contained in:
Christian Pauly 2021-12-26 11:30:44 +01:00
parent 71a2ff5170
commit 010607112d
3 changed files with 182 additions and 78 deletions

View File

@ -2668,5 +2668,6 @@
"whoCanSeeMyStories": "Who can see my stories?", "whoCanSeeMyStories": "Who can see my stories?",
"unsubscribeStories": "Unsubscribe stories", "unsubscribeStories": "Unsubscribe stories",
"thisUserHasNotPostedAnythingYet": "This user has not posted anything in their story yet", "thisUserHasNotPostedAnythingYet": "This user has not posted anything in their story yet",
"yourStory": "Your story" "yourStory": "Your story",
"replyHasBeenSent": "Reply has been sent"
} }

View File

@ -5,6 +5,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@ -32,12 +33,60 @@ class StoryPageController extends State<StoryPage> {
Timer? _progressTimer; Timer? _progressTimer;
bool loadingMode = false; bool loadingMode = false;
final TextEditingController replyController = TextEditingController();
final FocusNode replyFocus = FocusNode();
final List<Event> events = []; final List<Event> events = [];
Timeline? timeline; Timeline? timeline;
Event? get currentEvent => index < events.length ? events[index] : null; Event? get currentEvent => index < events.length ? events[index] : null;
bool replyLoading = false;
void replyEmojiAction() async {
if (replyLoading) return;
hold();
await showModalBottomSheet(
context: context,
builder: (context) => EmojiPicker(
onEmojiSelected: (c, e) {
Navigator.of(context).pop();
replyAction(e.emoji);
},
),
);
unhold();
}
void replyAction([String? message]) async {
message ??= replyController.text;
setState(() {
replyLoading = true;
});
try {
final client = Matrix.of(context).client;
final roomId = await client.startDirectChat(currentEvent!.senderId);
await client.getRoomById(roomId)!.sendTextEvent(
message,
inReplyTo: currentEvent!,
);
replyController.clear();
replyFocus.unfocus();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.replyHasBeenSent),
),
);
} catch (e, s) {
Logs().w('Unable to reply to story', e, s);
} finally {
setState(() {
replyLoading = false;
});
}
}
List<User> get currentSeenByUsers { List<User> get currentSeenByUsers {
final timeline = this.timeline; final timeline = this.timeline;
final currentEvent = this.currentEvent; final currentEvent = this.currentEvent;
@ -88,8 +137,6 @@ class StoryPageController extends State<StoryPage> {
); );
} }
final TextEditingController replyController = TextEditingController();
static const Duration _step = Duration(milliseconds: 50); static const Duration _step = Duration(milliseconds: 50);
static const Duration maxProgress = Duration(seconds: 5); static const Duration maxProgress = Duration(seconds: 5);
@ -145,13 +192,19 @@ class StoryPageController extends State<StoryPage> {
DateTime _holdedAt = DateTime.fromMicrosecondsSinceEpoch(0); DateTime _holdedAt = DateTime.fromMicrosecondsSinceEpoch(0);
void hold(_) { bool isHold = false;
void hold([_]) {
_holdedAt = DateTime.now(); _holdedAt = DateTime.now();
if (loadingMode) return; if (loadingMode) return;
_progressTimer?.cancel(); _progressTimer?.cancel();
setState(() {
isHold = true;
});
} }
void unhold([_]) { void unhold([_]) {
isHold = false;
if (DateTime.now().millisecondsSinceEpoch - if (DateTime.now().millisecondsSinceEpoch -
_holdedAt.millisecondsSinceEpoch < _holdedAt.millisecondsSinceEpoch <
200) { 200) {

View File

@ -26,7 +26,14 @@ class StoryView extends StatelessWidget {
backgroundColor: Colors.blueGrey, backgroundColor: Colors.blueGrey,
appBar: AppBar( appBar: AppBar(
titleSpacing: 0, titleSpacing: 0,
title: ListTile( leading: IconButton(
icon: const Icon(Icons.close),
onPressed: Navigator.of(context).pop,
),
title: AnimatedOpacity(
duration: const Duration(seconds: 1),
opacity: controller.isHold ? 0 : 1,
child: ListTile(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: Text( title: Text(
controller.title, controller.title,
@ -61,6 +68,7 @@ class StoryView extends StatelessWidget {
name: controller.title, name: controller.title,
), ),
), ),
),
systemOverlayStyle: SystemUiOverlayStyle.light, systemOverlayStyle: SystemUiOverlayStyle.light,
iconTheme: const IconThemeData(color: Colors.white), iconTheme: const IconThemeData(color: Colors.white),
elevation: 0, elevation: 0,
@ -199,6 +207,9 @@ class StoryView extends StatelessWidget {
top: 4, top: 4,
left: 4, left: 4,
right: 4, right: 4,
child: AnimatedOpacity(
duration: const Duration(seconds: 1),
opacity: controller.isHold ? 0 : 1,
child: SafeArea( child: SafeArea(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -228,6 +239,44 @@ class StoryView extends StatelessWidget {
), ),
), ),
), ),
),
if (!controller.isOwnStory && currentEvent != null)
Positioned(
bottom: 16,
left: 16,
right: 16,
child: AnimatedOpacity(
duration: const Duration(seconds: 1),
opacity: controller.isHold ? 0 : 1,
child: SafeArea(
child: TextField(
onTap: controller.hold,
onEditingComplete: controller.unhold,
focusNode: controller.replyFocus,
controller: controller.replyController,
minLines: 1,
maxLines: 7,
onSubmitted: controller.replyAction,
textInputAction: TextInputAction.newline,
readOnly: controller.replyLoading,
decoration: InputDecoration(
hintText: L10n.of(context)!.reply,
prefixIcon: IconButton(
onPressed: controller.replyEmojiAction,
icon: const Icon(Icons.emoji_emotions_outlined),
),
suffixIcon: controller.replyLoading
? const CircularProgressIndicator.adaptive(
strokeWidth: 2)
: IconButton(
onPressed: controller.replyAction,
icon: const Icon(Icons.send_outlined),
),
),
),
),
),
),
if (controller.isOwnStory && if (controller.isOwnStory &&
controller.currentSeenByUsers.isNotEmpty) controller.currentSeenByUsers.isNotEmpty)
Positioned( Positioned(
@ -248,7 +297,8 @@ class StoryView extends StatelessWidget {
), ),
), ),
), ),
)), ),
),
], ],
), ),
); );