Add new refresh status/request button to timeline page

codemagic-setup
Hank Grabowski 2023-01-29 10:14:34 -05:00
rodzic 90574a83d7
commit 1c6a712c15
5 zmienionych plików z 81 dodań i 51 usunięć

Wyświetl plik

@ -20,40 +20,35 @@ class TimelinePanel extends StatelessWidget {
return Center(child: Text('Error getting timeline: ${result.error}')); return Center(child: Text('Error getting timeline: ${result.error}'));
} }
final items = result.value; final items = result.value;
return RefreshIndicator( return ListView.separated(
onRefresh: () async { itemBuilder: (context, index) {
await manager.updateTimeline(timeline, TimelineRefreshType.refresh); if (index == 0) {
}, return TextButton(
child: ListView.separated( onPressed: () async => await manager.updateTimeline(
itemBuilder: (context, index) { timeline, TimelineRefreshType.loadNewer),
if (index == 0) { child: const Text('Load newer posts'));
return TextButton( }
onPressed: () async => await manager.updateTimeline(
timeline, TimelineRefreshType.loadNewer),
child: const Text('Load newer posts'));
}
if (index == items.length + 1) { if (index == items.length + 1) {
return TextButton( return TextButton(
onPressed: () async => await manager.updateTimeline( onPressed: () async => await manager.updateTimeline(
timeline, TimelineRefreshType.loadOlder), timeline, TimelineRefreshType.loadOlder),
child: const Text('Load older posts')); child: const Text('Load older posts'));
} }
final itemIndex = index - 1; final itemIndex = index - 1;
final item = items[itemIndex]; final item = items[itemIndex];
_logger.finest( _logger
'Building item: $itemIndex: ${item.entry.toShortString()}'); .finest('Building item: $itemIndex: ${item.entry.toShortString()}');
return PostControl( return PostControl(
originalItem: item, originalItem: item,
scrollToId: item.id, scrollToId: item.id,
openRemote: false, openRemote: false,
showStatusOpenButton: true, showStatusOpenButton: true,
isRoot: false, isRoot: false,
); );
}, },
separatorBuilder: (context, index) => Divider(), separatorBuilder: (context, index) => Divider(),
itemCount: items.length + 2, itemCount: items.length + 2,
),
); );
} }
} }

Wyświetl plik

@ -243,21 +243,25 @@ class FriendicaClient {
FutureResult<List<TimelineEntry>, ExecError> getUserTimeline( FutureResult<List<TimelineEntry>, ExecError> getUserTimeline(
{String userId = '', int page = 1, int count = 10}) async { {String userId = '', int page = 1, int count = 10}) async {
_logger.finest(() => 'Getting user timeline for $userId'); _logger.finest(() => 'Getting user timeline for $userId');
_networkStatusService.startTimelineLoading();
final baseUrl = 'https://$serverName/api/statuses/user_timeline?'; final baseUrl = 'https://$serverName/api/statuses/user_timeline?';
final pagingData = 'count=$count&page=$page'; final pagingData = 'count=$count&page=$page';
final url = userId.isEmpty final url = userId.isEmpty
? '$baseUrl$pagingData' ? '$baseUrl$pagingData'
: '${baseUrl}screen_name=$userId$pagingData'; : '${baseUrl}screen_name=$userId$pagingData';
final request = Uri.parse(url); final request = Uri.parse(url);
return (await _getApiListRequest(request).andThenSuccessAsync( final result = (await _getApiListRequest(request).andThenSuccessAsync(
(postsJson) async => postsJson.data (postsJson) async => postsJson.data
.map((json) => TimelineEntryMastodonExtensions.fromJson(json)) .map((json) => TimelineEntryMastodonExtensions.fromJson(json))
.toList())) .toList()))
.mapError((error) => error as ExecError); .execErrorCast();
_networkStatusService.finishTimelineLoading();
return result;
} }
FutureResult<List<TimelineEntry>, ExecError> getTimeline( FutureResult<List<TimelineEntry>, ExecError> getTimeline(
{required TimelineIdentifiers type, required PagingData page}) async { {required TimelineIdentifiers type, required PagingData page}) async {
_networkStatusService.startTimelineLoading();
final String timelinePath = _typeToTimelinePath(type); final String timelinePath = _typeToTimelinePath(type);
final String timelineQPs = _typeToTimelineQueryParameters(type); final String timelineQPs = _typeToTimelineQueryParameters(type);
final baseUrl = 'https://$serverName/api/v1/$timelinePath'; final baseUrl = 'https://$serverName/api/v1/$timelinePath';
@ -265,11 +269,13 @@ class FriendicaClient {
'$baseUrl?exclude_replies=true&${page.toQueryParameters()}&$timelineQPs'; '$baseUrl?exclude_replies=true&${page.toQueryParameters()}&$timelineQPs';
final request = Uri.parse(url); final request = Uri.parse(url);
_logger.finest(() => 'Getting ${type.toHumanKey()} with paging data $page'); _logger.finest(() => 'Getting ${type.toHumanKey()} with paging data $page');
return (await _getApiListRequest(request).andThenSuccessAsync( final result = (await _getApiListRequest(request).andThenSuccessAsync(
(postsJson) async => postsJson.data (postsJson) async => postsJson.data
.map((json) => TimelineEntryMastodonExtensions.fromJson(json)) .map((json) => TimelineEntryMastodonExtensions.fromJson(json))
.toList())) .toList()))
.execErrorCast(); .execErrorCast();
_networkStatusService.finishTimelineLoading();
return result;
} }
FutureResult<Uint8List, ExecError> getFileBytes(Uri url) async { FutureResult<Uint8List, ExecError> getFileBytes(Uri url) async {

Wyświetl plik

@ -6,8 +6,10 @@ import 'package:provider/provider.dart';
import '../controls/app_bottom_nav_bar.dart'; import '../controls/app_bottom_nav_bar.dart';
import '../controls/padding.dart'; import '../controls/padding.dart';
import '../controls/timeline/timeline_panel.dart'; import '../controls/timeline/timeline_panel.dart';
import '../globals.dart';
import '../models/TimelineIdentifiers.dart'; import '../models/TimelineIdentifiers.dart';
import '../models/group_data.dart'; import '../models/group_data.dart';
import '../services/network_status_service.dart';
import '../services/timeline_manager.dart'; import '../services/timeline_manager.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
@ -34,11 +36,13 @@ class _HomeScreenState extends State<HomeScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_logger.finest('Build'); _logger.finest('Build');
final groups = context final nss = getIt<NetworkStatusService>();
.watch<TimelineManager>() final manager = context.watch<TimelineManager>();
.getGroups() final groups = manager.getGroups().getValueOrElse(() => []).toList();
.getValueOrElse(() => []) final currentTimeline = TimelineIdentifiers(
.toList(); timeline: currentType,
auxData: currentGroup?.id ?? '',
);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Theme.of(context).canvasColor, backgroundColor: Theme.of(context).canvasColor,
@ -76,6 +80,30 @@ class _HomeScreenState extends State<HomeScreen> {
], ],
), ),
actions: [ actions: [
ValueListenableBuilder(
valueListenable: nss.timelineLoadingStatus,
builder: (context2, executing, _) {
if (executing) {
final theme = Theme.of(context);
final size = theme.appBarTheme.actionsIconTheme?.size ??
theme.iconTheme.size ??
24;
return Center(
child: SizedBox(
width: size,
height: size,
child: CircularProgressIndicator(),
),
);
}
return IconButton(
onPressed: () async => await manager.updateTimeline(
currentTimeline, TimelineRefreshType.refresh),
icon: Icon(
Icons.refresh,
color: Theme.of(context).textTheme.bodyText1!.color,
));
}),
IconButton( IconButton(
onPressed: () { onPressed: () {
context.push('/post/new'); context.push('/post/new');
@ -91,10 +119,7 @@ class _HomeScreenState extends State<HomeScreen> {
children: [ children: [
Expanded( Expanded(
child: TimelinePanel( child: TimelinePanel(
timeline: TimelineIdentifiers( timeline: currentTimeline,
timeline: currentType,
auxData: currentGroup?.id ?? '',
),
)), )),
], ],
), ),

Wyświetl plik

@ -1,18 +1,22 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
class NetworkStatusService { class NetworkStatusService {
static final _logger = Logger('$NetworkStatusService');
final notificationsUpdateStatus = ValueNotifier<bool>(false); final notificationsUpdateStatus = ValueNotifier<bool>(false);
final timelineLoadingStatus = ValueNotifier<bool>(false);
void startNotificationUpdate() { void startNotificationUpdate() {
_logger.info('Setting Notification Update status to true');
notificationsUpdateStatus.value = true; notificationsUpdateStatus.value = true;
} }
void finishNotificationUpdate() { void finishNotificationUpdate() {
_logger.info('Setting Notification Update status to false');
notificationsUpdateStatus.value = false; notificationsUpdateStatus.value = false;
} }
void startTimelineLoading() {
timelineLoadingStatus.value = true;
}
void finishTimelineLoading() {
timelineLoadingStatus.value = false;
}
} }

Wyświetl plik

@ -8,7 +8,7 @@ import Foundation
import desktop_window import desktop_window
import flutter_secure_storage_macos import flutter_secure_storage_macos
import objectbox_flutter_libs import objectbox_flutter_libs
import path_provider_macos import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
import sqflite import sqflite
import url_launcher_macos import url_launcher_macos