2022-12-16 20:41:15 +00:00
|
|
|
import 'package:flutter/material.dart';
|
2022-12-19 18:59:33 +00:00
|
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
2023-03-21 18:27:38 +00:00
|
|
|
import 'package:result_monad/result_monad.dart';
|
2022-12-19 18:59:33 +00:00
|
|
|
|
2023-04-27 19:19:51 +00:00
|
|
|
import '../controls/html_text_viewer_control.dart';
|
2023-03-20 14:06:44 +00:00
|
|
|
import '../controls/login_aware_cached_network_image.dart';
|
2022-12-19 18:59:33 +00:00
|
|
|
import '../controls/padding.dart';
|
2023-03-21 18:27:38 +00:00
|
|
|
import '../globals.dart';
|
2022-12-19 18:59:33 +00:00
|
|
|
import '../models/connection.dart';
|
2023-03-21 18:27:38 +00:00
|
|
|
import '../models/exec_error.dart';
|
|
|
|
import '../routes.dart';
|
2022-12-19 18:59:33 +00:00
|
|
|
import '../services/connections_manager.dart';
|
2023-03-21 18:27:38 +00:00
|
|
|
import '../services/feature_version_checker.dart';
|
|
|
|
import '../services/follow_requests_manager.dart';
|
2023-05-03 19:49:40 +00:00
|
|
|
import '../services/network_status_service.dart';
|
2023-03-21 18:27:38 +00:00
|
|
|
import '../services/notifications_manager.dart';
|
|
|
|
import '../utils/active_profile_selector.dart';
|
|
|
|
import '../utils/url_opening_utils.dart';
|
2022-12-19 18:59:33 +00:00
|
|
|
|
|
|
|
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;
|
2022-12-16 20:41:15 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2023-05-03 19:49:40 +00:00
|
|
|
final nss = getIt<NetworkStatusService>();
|
2023-03-21 18:27:38 +00:00
|
|
|
final fm =
|
|
|
|
getIt<ActiveProfileSelector<FollowRequestsManager>>().activeEntry.value;
|
|
|
|
final cm = context
|
2023-03-15 17:56:52 +00:00
|
|
|
.watch<ActiveProfileSelector<ConnectionsManager>>()
|
|
|
|
.activeEntry
|
|
|
|
.value;
|
2023-03-21 18:27:38 +00:00
|
|
|
|
|
|
|
late final Result<Connection, ExecError> result;
|
|
|
|
if (getIt<FriendicaVersionChecker>()
|
|
|
|
.canUseFeature(RelaticaFeatures.usingActualFollowRequests)) {
|
|
|
|
result = fm
|
|
|
|
.getByUserId(widget.userId)
|
|
|
|
.mapValue((request) => request.connection);
|
|
|
|
} else {
|
2023-04-28 01:48:01 +00:00
|
|
|
result = cm.getById(widget.userId, forceUpdate: true);
|
2022-12-19 18:59:33 +00:00
|
|
|
}
|
|
|
|
|
2023-03-21 18:27:38 +00:00
|
|
|
late final Widget body;
|
|
|
|
if (result.isFailure) {
|
2023-05-04 14:37:32 +00:00
|
|
|
if (result.error.type == ErrorType.notFound &&
|
|
|
|
nss.connectionUpdateStatus.value) {
|
|
|
|
fm.update();
|
|
|
|
body = const Text('Loading...');
|
|
|
|
} else {
|
|
|
|
body = Text('Error getting request info: ${result.error}');
|
|
|
|
}
|
2023-03-21 18:27:38 +00:00
|
|
|
} else {
|
|
|
|
final contact = result.value;
|
|
|
|
final contactStatus = cm
|
2023-04-28 01:48:01 +00:00
|
|
|
.getById(widget.userId, forceUpdate: true)
|
2023-03-21 18:27:38 +00:00
|
|
|
.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:
|
2023-05-03 19:49:40 +00:00
|
|
|
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.',
|
|
|
|
);
|
2023-03-21 18:27:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-12-19 18:59:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
|
|
|
title: const Text(
|
|
|
|
'Accept Request?',
|
|
|
|
)),
|
|
|
|
body: Padding(
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
child: Center(child: body),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildMainPanel(
|
2023-03-21 18:27:38 +00:00
|
|
|
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,
|
2023-10-31 01:44:16 +00:00
|
|
|
pathParameters: {'id': contact.id},
|
2023-03-21 18:27:38 +00:00
|
|
|
),
|
|
|
|
child: const Text('Posts')),
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: () async =>
|
|
|
|
await openProfileExternal(context, contact),
|
|
|
|
child: const Text('Open In Browser'),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const VerticalPadding(),
|
2023-04-27 19:19:51 +00:00
|
|
|
HtmlTextViewerControl(
|
|
|
|
content: contact.note,
|
2023-03-21 18:27:38 +00:00
|
|
|
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"}'),
|
|
|
|
],
|
|
|
|
),
|
2022-12-19 18:59:33 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> accept(
|
|
|
|
ConnectionsManager manager,
|
2023-03-21 18:27:38 +00:00
|
|
|
FollowRequestsManager followRequestsManager,
|
2022-12-19 18:59:33 +00:00
|
|
|
Connection contact,
|
|
|
|
bool followBack,
|
|
|
|
) async {
|
|
|
|
setState(() {
|
|
|
|
processing = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
await manager.acceptFollowRequest(contact);
|
|
|
|
if (followBack) {
|
|
|
|
await manager.follow(contact);
|
|
|
|
}
|
|
|
|
|
2023-03-21 18:27:38 +00:00
|
|
|
_performUpdates(followRequestsManager);
|
|
|
|
|
2022-12-19 18:59:33 +00:00
|
|
|
setState(() {
|
|
|
|
processing = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (mounted && context.canPop()) {
|
|
|
|
context.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-21 18:27:38 +00:00
|
|
|
Future<void> reject(ConnectionsManager manager,
|
|
|
|
FollowRequestsManager followRequestsManager, Connection contact) async {
|
2022-12-19 18:59:33 +00:00
|
|
|
setState(() {
|
|
|
|
processing = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
await manager.rejectFollowRequest(contact);
|
|
|
|
|
2023-03-21 18:27:38 +00:00
|
|
|
_performUpdates(followRequestsManager);
|
2022-12-19 18:59:33 +00:00
|
|
|
setState(() {
|
|
|
|
processing = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (mounted && context.canPop()) {
|
|
|
|
context.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-21 18:27:38 +00:00
|
|
|
Future<void> ignore(ConnectionsManager manager,
|
|
|
|
FollowRequestsManager followRequestsManager, Connection contact) async {
|
2022-12-19 18:59:33 +00:00
|
|
|
setState(() {
|
|
|
|
processing = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
await manager.ignoreFollowRequest(contact);
|
2023-03-21 18:27:38 +00:00
|
|
|
_performUpdates(followRequestsManager);
|
2022-12-19 18:59:33 +00:00
|
|
|
|
|
|
|
setState(() {
|
|
|
|
processing = false;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (mounted && context.canPop()) {
|
|
|
|
context.pop();
|
|
|
|
}
|
2022-12-16 20:41:15 +00:00
|
|
|
}
|
2023-03-21 18:27:38 +00:00
|
|
|
|
|
|
|
void _performUpdates(FollowRequestsManager followRequestsManager) {
|
|
|
|
followRequestsManager.update();
|
|
|
|
getIt<ActiveProfileSelector<NotificationsManager>>()
|
|
|
|
.activeEntry
|
2023-08-04 16:34:51 +00:00
|
|
|
.andThenSuccess((m) => m.refreshNotifications());
|
2023-03-21 18:27:38 +00:00
|
|
|
}
|
2022-12-16 20:41:15 +00:00
|
|
|
}
|