Add initial likes/refresh viewing capability

codemagic-setup
Hank Grabowski 2023-01-31 14:39:06 -05:00
rodzic 089fca1790
commit a8ef7bb670
8 zmienionych plików z 202 dodań i 16 usunięć

Wyświetl plik

@ -172,17 +172,24 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
Row(
children: [
TextButton(
onPressed: likes == 0 ? null : () {},
onPressed: likes == 0
? null
: () {
context.push('/likes/${widget.entry.id}');
},
child: Text('$likes likes'),
),
TextButton(
onPressed: reshares == 0 ? null : () {},
onPressed: reshares == 0
? null
: () {
context.push('/reshares/${widget.entry.id}');
},
child: Text('$reshares reshares'),
),
Text('$comments comments'),
],
),
Text('$likes likes, $reshares reshares, $comments comments'),
Row(children: [
IconButton(
onPressed:

Wyświetl plik

@ -16,6 +16,7 @@ import 'services/direct_message_service.dart';
import 'services/entry_manager_service.dart';
import 'services/gallery_service.dart';
import 'services/hashtag_service.dart';
import 'services/interactions_manager.dart';
import 'services/media_upload_attachment_helper.dart';
import 'services/network_status_service.dart';
import 'services/notifications_manager.dart';
@ -55,7 +56,9 @@ Future<void> dependencyInjectionInitialization() async {
galleryService.getGalleries();
getIt.registerLazySingleton<DirectMessageService>(
() => DirectMessageService());
getIt.registerLazySingleton(() => NetworkStatusService());
getIt.registerLazySingleton<NetworkStatusService>(
() => NetworkStatusService());
getIt.registerLazySingleton<InteractionsManager>(() => InteractionsManager());
await secretsService.initialize().andThenSuccessAsync((credentials) async {
if (credentials.isEmpty) {

Wyświetl plik

@ -334,6 +334,44 @@ class FriendicaClient {
.execErrorCastAsync();
}
// TODO Convert getLikes to using paging for real
FutureResult<List<Connection>, ExecError> getLikes(String id) async {
_networkStatusService.startInteractionsLoading();
final result = (await runCatchingAsync(() async {
final url = 'https://$serverName/api/v1/statuses/$id/favourited_by';
final request = Uri.parse('$url');
_logger.finest(() => 'Getting favorites for status $id');
return (await _getApiListRequest(request)
.andThenSuccessAsync((jsonArray) async {
return jsonArray.data
.map((p) => ConnectionMastodonExtensions.fromJson(p))
.toList();
}));
}))
.execErrorCastAsync();
_networkStatusService.finishInteractionsLoading();
return result;
}
// TODO Convert getReshares to using paging for real
FutureResult<List<Connection>, ExecError> getReshares(String id) async {
_networkStatusService.startInteractionsLoading();
final result = (await runCatchingAsync(() async {
final url = 'https://$serverName/api/v1/statuses/$id/reblogged_by';
final request = Uri.parse('$url');
_logger.finest(() => 'Getting rebloggers for status $id');
return (await _getApiListRequest(request)
.andThenSuccessAsync((jsonArray) async {
return jsonArray.data
.map((p) => ConnectionMastodonExtensions.fromJson(p))
.toList();
}));
}))
.execErrorCastAsync();
_networkStatusService.finishInteractionsLoading();
return result;
}
FutureResult<bool, ExecError> deleteEntryById(String id) async {
_logger.finest(() => 'Deleting post/comment $id');
final url = 'https://$serverName/api/v1/statuses/$id';

Wyświetl plik

@ -13,6 +13,7 @@ import 'services/direct_message_service.dart';
import 'services/entry_manager_service.dart';
import 'services/gallery_service.dart';
import 'services/hashtag_service.dart';
import 'services/interactions_manager.dart';
import 'services/notifications_manager.dart';
import 'services/setting_service.dart';
import 'services/timeline_manager.dart';
@ -79,6 +80,9 @@ class App extends StatelessWidget {
),
ChangeNotifierProvider<DirectMessageService>(
create: (_) => getIt<DirectMessageService>(),
),
ChangeNotifierProvider<InteractionsManager>(
create: (_) => getIt<InteractionsManager>(),
)
],
child: MaterialApp.router(

Wyświetl plik

@ -223,7 +223,7 @@ final appRouter = GoRouter(
path: '/likes/:id',
name: ScreenPaths.likes,
builder: (context, state) => InteractionsViewerScreen(
entryId: state.params['id']!,
statusId: state.params['id']!,
type: InteractionType.like,
),
),
@ -231,7 +231,7 @@ final appRouter = GoRouter(
path: '/reshares/:id',
name: ScreenPaths.reshares,
builder: (context, state) => InteractionsViewerScreen(
entryId: state.params['id']!,
statusId: state.params['id']!,
type: InteractionType.reshare,
),
),

Wyświetl plik

@ -1,27 +1,84 @@
import 'package:flutter/material.dart';
import 'package:relatica/controls/standard_appbar.dart';
import 'package:relatica/models/interaction_type_enum.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
import '../controls/image_control.dart';
import '../controls/standard_appbar.dart';
import '../controls/status_and_refresh_button.dart';
import '../globals.dart';
import '../models/connection.dart';
import '../models/exec_error.dart';
import '../models/interaction_type_enum.dart';
import '../routes.dart';
import '../services/interactions_manager.dart';
import '../services/network_status_service.dart';
class InteractionsViewerScreen extends StatelessWidget {
final String entryId;
final String statusId;
final InteractionType type;
const InteractionsViewerScreen({
super.key,
required this.entryId,
required this.statusId,
required this.type,
});
List<Connection> getInteractors(InteractionsManager manager) {
switch (type) {
case InteractionType.like:
return manager.getLikes(statusId);
case InteractionType.reshare:
return manager.getReshares(statusId);
}
}
FutureResult<List<Connection>, ExecError> refreshInteractors(
InteractionsManager manager) async {
switch (type) {
case InteractionType.like:
return await manager.updateLikesForStatus(statusId);
case InteractionType.reshare:
return await manager.updateResharesForStatus(statusId);
}
}
@override
Widget build(BuildContext context) {
final nss = getIt<NetworkStatusService>();
final manager = context.watch<InteractionsManager>();
final connections = getInteractors(manager);
return Scaffold(
appBar: StandardAppBar.build(context, buildTitle()),
appBar: StandardAppBar.build(context, buildTitle(), actions: [
StatusAndRefreshButton(
valueListenable: nss.interactionsLoadingStatus,
refreshFunction: () async => await refreshInteractors(manager),
busyColor: Theme.of(context).colorScheme.background,
)
]),
body: Center(
child: Column(
children: [
Text(buildTitle()),
],
)),
child: ListView.separated(
itemCount: connections.length,
itemBuilder: (context, index) {
final connection = connections[index];
return ListTile(
onTap: () {
context.pushNamed(ScreenPaths.userProfile,
params: {'id': connection.id});
},
leading: ImageControl(
imageUrl: connection.avatarUrl.toString(),
iconOverride: const Icon(Icons.person),
width: 32.0,
onTap: () => context.pushNamed(ScreenPaths.userProfile,
params: {'id': connection.id}),
),
title: Text('${connection.name} (${connection.handle})'),
);
},
separatorBuilder: (_, __) => const Divider(),
),
),
);
}

Wyświetl plik

@ -0,0 +1,68 @@
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:result_monad/result_monad.dart';
import '../globals.dart';
import '../models/connection.dart';
import '../models/exec_error.dart';
import 'auth_service.dart';
class InteractionsManager extends ChangeNotifier {
static final _logger = Logger('$InteractionsManager');
final _likesByStatusId = <String, List<Connection>>{};
final _resharesByStatusId = <String, List<Connection>>{};
List<Connection> getLikes(String statusId) {
if (!_likesByStatusId.containsKey(statusId)) {
updateLikesForStatus(statusId);
return [];
}
return _likesByStatusId[statusId]!;
}
List<Connection> getReshares(String statusId) {
if (!_resharesByStatusId.containsKey(statusId)) {
updateResharesForStatus(statusId);
return [];
}
return _resharesByStatusId[statusId]!;
}
FutureResult<List<Connection>, ExecError> updateLikesForStatus(
String statusId) async {
final auth = getIt<AuthService>();
final clientResult = auth.currentClient;
if (clientResult.isFailure) {
_logger.severe('Error getting Friendica client: ${clientResult.error}');
return clientResult.errorCast();
}
final client = clientResult.value;
final likesResult = await client.getLikes(statusId);
if (likesResult.isSuccess) {
_likesByStatusId[statusId] = likesResult.value;
notifyListeners();
}
return likesResult;
}
FutureResult<List<Connection>, ExecError> updateResharesForStatus(
String statusId) async {
final auth = getIt<AuthService>();
final clientResult = auth.currentClient;
if (clientResult.isFailure) {
_logger.severe('Error getting Friendica client: ${clientResult.error}');
return clientResult.errorCast();
}
final client = clientResult.value;
final resharesResult = await client.getReshares(statusId);
if (resharesResult.isSuccess) {
_resharesByStatusId[statusId] = resharesResult.value;
notifyListeners();
}
return resharesResult;
}
}

Wyświetl plik

@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
class NetworkStatusService {
final notificationsUpdateStatus = ValueNotifier<bool>(false);
final interactionsLoadingStatus = ValueNotifier<bool>(false);
final timelineLoadingStatus = ValueNotifier<bool>(false);
final imageGalleryLoadingStatus = ValueNotifier<bool>(false);
@ -28,4 +29,12 @@ class NetworkStatusService {
void finishGalleryLoading() {
imageGalleryLoadingStatus.value = false;
}
void startInteractionsLoading() {
interactionsLoadingStatus.value = true;
}
void finishInteractionsLoading() {
interactionsLoadingStatus.value = false;
}
}