From 6b7bf600f8e35c5130c81f9341e34fb1550be0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Sun, 26 May 2024 19:24:19 +0200 Subject: [PATCH] channel list --- flutter/lib/api/api_client.dart | 8 +- .../lib/pages/channel_list/channel_list.dart | 18 ++-- .../pages/channel_list/channel_list_item.dart | 85 +++++++++++++++++-- .../lib/pages/message_list/message_list.dart | 25 +++--- 4 files changed, 114 insertions(+), 22 deletions(-) diff --git a/flutter/lib/api/api_client.dart b/flutter/lib/api/api_client.dart index 123e486..c2056d2 100644 --- a/flutter/lib/api/api_client.dart +++ b/flutter/lib/api/api_client.dart @@ -146,12 +146,16 @@ class APIClient { ); } - static Future<(String, List)> getMessageList(KeyTokenAuth auth, String pageToken, int? pageSize) async { + static Future<(String, List)> getMessageList(KeyTokenAuth auth, String pageToken, {int? pageSize, List? channelIDs}) async { return await _request( name: 'getMessageList', method: 'GET', relURL: 'messages', - query: {'next_page_token': pageToken, if (pageSize != null) 'page_size': pageSize.toString()}, + query: { + 'next_page_token': pageToken, + if (pageSize != null) 'page_size': pageSize.toString(), + if (channelIDs != null) 'channel_id': channelIDs.join(","), + }, fn: (json) => Message.fromPaginatedJsonArray(json, 'messages', 'next_page_token'), auth: auth, ); diff --git a/flutter/lib/pages/channel_list/channel_list.dart b/flutter/lib/pages/channel_list/channel_list.dart index e341a41..677b524 100644 --- a/flutter/lib/pages/channel_list/channel_list.dart +++ b/flutter/lib/pages/channel_list/channel_list.dart @@ -44,6 +44,8 @@ class _ChannelRootPageState extends State { try { final items = await APIClient.getChannelList(acc.auth!, ChannelSelector.all); + items.sort((a, b) => -1 * (a.timestampLastSent ?? '').compareTo(b.timestampLastSent ?? '')); + _pagingController.appendLastPage(items); } catch (exc, trace) { _pagingController.error = exc.toString(); @@ -53,11 +55,17 @@ class _ChannelRootPageState extends State { @override Widget build(BuildContext context) { - return PagedListView( - pagingController: _pagingController, - builderDelegate: PagedChildBuilderDelegate( - itemBuilder: (context, item, index) => ChannelListItem( - channel: item, + return RefreshIndicator( + onRefresh: () => Future.sync( + () => _pagingController.refresh(), + ), + child: PagedListView( + pagingController: _pagingController, + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (context, item, index) => ChannelListItem( + channel: item, + onPressed: () {/*TODO*/}, + ), ), ), ); diff --git a/flutter/lib/pages/channel_list/channel_list_item.dart b/flutter/lib/pages/channel_list/channel_list_item.dart index aa765f2..d5db1b0 100644 --- a/flutter/lib/pages/channel_list/channel_list_item.dart +++ b/flutter/lib/pages/channel_list/channel_list_item.dart @@ -1,17 +1,92 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:simplecloudnotifier/api/api_client.dart'; import 'package:simplecloudnotifier/models/channel.dart'; +import 'package:simplecloudnotifier/models/message.dart'; +import 'package:simplecloudnotifier/state/user_account.dart'; + +class ChannelListItem extends StatefulWidget { + static final _dateFormat = DateFormat('yyyy-MM-dd kk:mm'); -class ChannelListItem extends StatelessWidget { const ChannelListItem({ required this.channel, + required this.onPressed, super.key, }); final Channel channel; + final Null Function() onPressed; @override - Widget build(BuildContext context) => ListTile( - leading: const SizedBox(width: 40, height: 40, child: const Placeholder()), - title: Text(channel.internalName), - ); + State createState() => _ChannelListItemState(); +} + +class _ChannelListItemState extends State { + Message? lastMessage; + + @override + void initState() { + super.initState(); + + final acc = Provider.of(context, listen: false); + + if (acc.auth != null) { + () async { + final (_, channelMessages) = await APIClient.getMessageList(acc.auth!, '@start', pageSize: 1, channelIDs: [widget.channel.channelID]); + setState(() { + lastMessage = channelMessages.firstOrNull; + }); + }(); + } + } + + @override + Widget build(BuildContext context) { + //TODO subscription status + return Card.filled( + margin: EdgeInsets.fromLTRB(0, 4, 0, 4), + shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)), + color: Theme.of(context).cardTheme.color, + child: InkWell( + splashColor: Theme.of(context).splashColor, + onTap: widget.onPressed, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Expanded( + child: Text( + widget.channel.displayName, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Text( + (widget.channel.timestampLastSent == null) ? '' : ChannelListItem._dateFormat.format(DateTime.parse(widget.channel.timestampLastSent!).toLocal()), + style: const TextStyle(fontSize: 14), + ), + ], + ), + SizedBox(height: 4), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Text( + lastMessage?.title ?? '...', + style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)), + ), + ), + Text(widget.channel.messagesSent.toString(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)), + ], + ), + ], + ), + ), + ), + ); + } } diff --git a/flutter/lib/pages/message_list/message_list.dart b/flutter/lib/pages/message_list/message_list.dart index f63ec8d..75d219a 100644 --- a/flutter/lib/pages/message_list/message_list.dart +++ b/flutter/lib/pages/message_list/message_list.dart @@ -51,7 +51,7 @@ class _MessageListPageState extends State { _channels = {for (var v in channels) v.channelID: v}; } - final (npt, newItems) = await APIClient.getMessageList(acc.auth!, thisPageToken, _pageSize); + final (npt, newItems) = await APIClient.getMessageList(acc.auth!, thisPageToken, pageSize: _pageSize); if (npt == '@end') { _pagingController.appendLastPage(newItems); @@ -68,15 +68,20 @@ class _MessageListPageState extends State { Widget build(BuildContext context) { return Padding( padding: EdgeInsets.fromLTRB(8, 4, 8, 4), - child: PagedListView( - pagingController: _pagingController, - builderDelegate: PagedChildBuilderDelegate( - itemBuilder: (context, item, index) => MessageListItem( - message: item, - allChannels: _channels ?? {}, - onPressed: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => MessageViewPage(message: item))); - }, + child: RefreshIndicator( + onRefresh: () => Future.sync( + () => _pagingController.refresh(), + ), + child: PagedListView( + pagingController: _pagingController, + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (context, item, index) => MessageListItem( + message: item, + allChannels: _channels ?? {}, + onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (context) => MessageViewPage(message: item))); + }, + ), ), ), ),