relatica/lib/screens/follow_request_adjudication...

268 wiersze
8.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.dart';
import '../controls/html_text_viewer_control.dart';
import '../controls/login_aware_cached_network_image.dart';
import '../controls/padding.dart';
import '../globals.dart';
import '../models/connection.dart';
import '../models/exec_error.dart';
import '../routes.dart';
import '../services/connections_manager.dart';
import '../services/feature_version_checker.dart';
import '../services/follow_requests_manager.dart';
import '../services/network_status_service.dart';
import '../services/notifications_manager.dart';
import '../utils/active_profile_selector.dart';
import '../utils/url_opening_utils.dart';
class FollowRequestAdjudicationScreen extends StatefulWidget {
final String userId;
const FollowRequestAdjudicationScreen({super.key, required this.userId});
@override
State<FollowRequestAdjudicationScreen> createState() =>
_FollowRequestAdjudicationScreenState();
}
class _FollowRequestAdjudicationScreenState
extends State<FollowRequestAdjudicationScreen> {
var processing = false;
@override
Widget build(BuildContext context) {
final nss = getIt<NetworkStatusService>();
final fm =
getIt<ActiveProfileSelector<FollowRequestsManager>>().activeEntry.value;
final cm = context
.watch<ActiveProfileSelector<ConnectionsManager>>()
.activeEntry
.value;
late final Result<Connection, ExecError> result;
if (getIt<FriendicaVersionChecker>()
.canUseFeature(RelaticaFeatures.usingActualFollowRequests)) {
result = fm
.getByUserId(widget.userId)
.mapValue((request) => request.connection);
} else {
result = cm.getById(widget.userId, forceUpdate: true);
}
late final Widget body;
if (result.isFailure) {
if (result.error.type == ErrorType.notFound &&
nss.connectionUpdateStatus.value) {
fm.update();
body = const Text('Loading...');
} else {
body = Text('Error getting request info: ${result.error}');
}
} else {
final contact = result.value;
final contactStatus = cm
.getById(widget.userId, forceUpdate: true)
.getValueOrElse(() => Connection(status: ConnectionStatus.none))
.status;
switch (contactStatus) {
case ConnectionStatus.theyFollowYou:
case ConnectionStatus.youFollowThem:
case ConnectionStatus.none:
body = _buildMainPanel(context, contact, cm, fm);
break;
case ConnectionStatus.mutual:
body = const Text('Already allowed them to connect');
break;
case ConnectionStatus.you:
case ConnectionStatus.unknown:
body = Text(nss.connectionUpdateStatus.value
? 'Loading...'
: 'Invalid state, nothing to do here: ${contact.status}');
break;
case ConnectionStatus.blocked:
// we should never get here because a blocked user shouldn't be allowed to create a connection request.
body = const Text(
'Use is blocked. Unblock to accept connection request.',
);
break;
}
}
return Scaffold(
appBar: AppBar(
title: const Text(
'Accept Request?',
)),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: body),
),
);
}
Widget _buildMainPanel(
BuildContext context,
Connection contact,
ConnectionsManager connectionsManager,
FollowRequestsManager followRequestsManager,
) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
LoginAwareCachedNetworkImage(imageUrl: contact.avatarUrl.toString()),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${contact.name}(${contact.handle})',
style: Theme.of(context).textTheme.titleLarge,
),
const HorizontalPadding(),
],
),
const VerticalPadding(),
Wrap(
runSpacing: 5.0,
spacing: 5.0,
alignment: WrapAlignment.center,
children: [
ElevatedButton(
onPressed: processing
? null
: () async => await accept(connectionsManager,
followRequestsManager, contact, true),
child: const Text('Accept and follow back'),
),
ElevatedButton(
onPressed: processing
? null
: () async => accept(connectionsManager,
followRequestsManager, contact, false),
child: const Text("Accept but don't follow back"),
),
ElevatedButton(
onPressed: processing
? null
: () async => reject(
connectionsManager, followRequestsManager, contact),
child: const Text('Reject'),
),
ElevatedButton(
onPressed: processing
? null
: () async => ignore(
connectionsManager, followRequestsManager, contact),
child: const Text('Ignore (Rejects but user cannot ask again)'),
),
],
),
const VerticalPadding(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () => context.pushNamed(
ScreenPaths.userPosts,
pathParameters: {'id': contact.id},
),
child: const Text('Posts')),
ElevatedButton(
onPressed: () async =>
await openProfileExternal(context, contact),
child: const Text('Open In Browser'),
),
],
),
const VerticalPadding(),
HtmlTextViewerControl(
content: contact.note,
onTapUrl: (url) async {
return await openUrlStringInSystembrowser(context, url, 'link');
},
),
const VerticalPadding(),
Text(
'#Followers: ${contact.followerCount} followers, #Following, ${contact.followingCount}, #Statuses: ${contact.statusesCount}'),
const VerticalPadding(),
Text('Last Status: ${contact.lastStatus ?? "Unknown"}'),
],
),
);
}
Future<void> accept(
ConnectionsManager manager,
FollowRequestsManager followRequestsManager,
Connection contact,
bool followBack,
) async {
setState(() {
processing = true;
});
await manager.acceptFollowRequest(contact);
if (followBack) {
await manager.follow(contact);
}
_performUpdates(followRequestsManager);
setState(() {
processing = false;
});
if (mounted && context.canPop()) {
context.pop();
}
}
Future<void> reject(ConnectionsManager manager,
FollowRequestsManager followRequestsManager, Connection contact) async {
setState(() {
processing = true;
});
await manager.rejectFollowRequest(contact);
_performUpdates(followRequestsManager);
setState(() {
processing = false;
});
if (mounted && context.canPop()) {
context.pop();
}
}
Future<void> ignore(ConnectionsManager manager,
FollowRequestsManager followRequestsManager, Connection contact) async {
setState(() {
processing = true;
});
await manager.ignoreFollowRequest(contact);
_performUpdates(followRequestsManager);
setState(() {
processing = false;
});
if (mounted && context.canPop()) {
context.pop();
}
}
void _performUpdates(FollowRequestsManager followRequestsManager) {
followRequestsManager.update();
getIt<ActiveProfileSelector<NotificationsManager>>()
.activeEntry
.andThenSuccess((m) => m.refreshNotifications());
}
}