Merge branch 'krille/improvestories' into 'main'

chore: Improve stories

See merge request famedly/fluffychat!641
This commit is contained in:
Krille Fear 2021-12-25 13:26:41 +00:00
commit 48a5c52a94
4 changed files with 78 additions and 20 deletions

View File

@ -89,6 +89,7 @@ class AddStoryView extends StatelessWidget {
controller: controller.controller,
minLines: 1,
maxLines: 20,
autofocus: true,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,

View File

@ -26,6 +26,7 @@ class StoriesHeader extends StatelessWidget {
void _contextualActions(BuildContext context, Room room) async {
final action = await showModalActionSheet<ContextualRoomAction>(
cancelLabel: L10n.of(context)!.cancel,
context: context,
actions: [
if (room.pushRuleState != PushRuleState.notify)
@ -105,19 +106,24 @@ class StoriesHeader extends StatelessWidget {
child: const Icon(Icons.add),
),
...client.storiesRooms.map(
(room) => _StoryButton(
label: room.creatorDisplayname,
child: Avatar(
mxContent: room
.getState(EventTypes.RoomCreate)!
.sender
.avatarUrl,
name: room.creatorDisplayname,
(room) => Opacity(
opacity: room.hasPosts ? 1 : 0.5,
child: _StoryButton(
label: room.creatorDisplayname,
child: Avatar(
mxContent: room
.getState(EventTypes.RoomCreate)!
.sender
.avatarUrl,
name: room.creatorDisplayname,
),
unread: room.notificationCount > 0 ||
room.membership == Membership.invite,
onPressed: () => room.hasPosts
? _goToStoryAction(context, room.id)
: _contextualActions(context, room),
onLongPressed: () => _contextualActions(context, room),
),
unread: room.notificationCount > 0 ||
room.membership == Membership.invite,
onPressed: () => _goToStoryAction(context, room.id),
onLongPressed: () => _contextualActions(context, room),
),
),
],
@ -130,6 +136,17 @@ class StoriesHeader extends StatelessWidget {
extension on Room {
String get creatorDisplayname =>
getState(EventTypes.RoomCreate)!.sender.calcDisplayname();
bool get hasPosts {
final lastEvent = this.lastEvent;
if (lastEvent == null) return false;
if (lastEvent.type != EventTypes.Message) return false;
if (DateTime.now().difference(lastEvent.originServerTs).inHours >
ClientStoriesExtension.lifeTimeInHours) {
return false;
}
return true;
}
}
class _StoryButton extends StatelessWidget {

View File

@ -29,6 +29,12 @@ class StoryPageController extends State<StoryPage> {
Timer? _progressTimer;
bool loadingMode = false;
final List<Event> events = [];
Event? get currentEvent => index < events.length ? events[index] : null;
final TextEditingController replyController = TextEditingController();
static const Duration _step = Duration(milliseconds: 50);
static const Duration maxProgress = Duration(seconds: 5);
@ -127,11 +133,11 @@ class StoryPageController extends State<StoryPage> {
.calcDisplayname() ??
'Story not found';
Future<List<Event>>? loadStory;
Future<void>? loadStory;
Future<List<Event>> _loadStory() async {
Future<void> _loadStory() async {
final room = Matrix.of(context).client.getRoomById(roomId);
if (room == null) return [];
if (room == null) return;
if (room.membership != Membership.join) {
final joinedFuture = room.client.onSync.stream
.where((u) => u.rooms?.join?.containsKey(room.id) ?? false)
@ -140,6 +146,7 @@ class StoryPageController extends State<StoryPage> {
await joinedFuture;
}
final timeline = await room.getTimeline();
timeline.requestKeys();
var events =
timeline.events.where((e) => e.type == EventTypes.Message).toList();
@ -171,7 +178,24 @@ class StoryPageController extends State<StoryPage> {
.forEach((event) => downloadAndDecryptAttachment(event,
event.messageType == MessageTypes.Video && PlatformInfos.isMobile));
return events.reversed.toList();
if (!events.last.receipts
.any((receipt) => receipt.user.id == room.client.userID)) {
for (var j = 0; j < events.length; j++) {
if (events[j]
.receipts
.any((receipt) => receipt.user.id == room.client.userID)) {
index = j;
room.setReadMarker(
events[index].eventId,
mRead: events[index].eventId,
);
break;
}
}
}
this.events.clear();
this.events.addAll(events.reversed.toList());
return;
}
@override

View File

@ -9,6 +9,7 @@ import 'package:matrix/matrix.dart';
import 'package:video_player/video_player.dart';
import 'package:fluffychat/pages/story/story_page.dart';
import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/string_color.dart';
@ -20,6 +21,7 @@ class StoryView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final currentEvent = controller.currentEvent;
return Scaffold(
appBar: AppBar(
titleSpacing: 0,
@ -29,7 +31,6 @@ class StoryView extends StatelessWidget {
controller.title,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
shadows: [
Shadow(
color: Colors.black,
@ -39,6 +40,21 @@ class StoryView extends StatelessWidget {
],
),
),
subtitle: currentEvent != null
? Text(
currentEvent.originServerTs.localizedTime(context),
style: const TextStyle(
color: Colors.white70,
shadows: [
Shadow(
color: Colors.black,
offset: Offset(0, 0),
blurRadius: 5,
),
],
),
)
: null,
leading: Avatar(
mxContent: controller.avatar,
name: controller.title,
@ -50,15 +66,15 @@ class StoryView extends StatelessWidget {
backgroundColor: Colors.transparent,
),
extendBodyBehindAppBar: true,
body: FutureBuilder<List<Event>>(
body: FutureBuilder(
future: controller.loadStory,
builder: (context, snapshot) {
final error = snapshot.error;
if (error != null) {
return Center(child: Text(error.toLocalizedString(context)));
}
final events = snapshot.data;
if (events == null) {
final events = controller.events;
if (snapshot.connectionState != ConnectionState.done) {
return const Center(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,