relatica/lib/screens/follow_request_adjudication...

266 wiersze
8.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:result_monad/result_monad.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/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 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);
}
late final Widget body;
if (result.isFailure) {
body = Text('Error getting request info: ${result.error}');
} else {
final contact = result.value;
final contactStatus = cm
.getById(widget.userId)
.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('Invalid state, nothing to do here: ${contact.status}');
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,
) {
// Options are:
// Accept and follow back
// Accept and don't follow back
// Reject
// Back with no action
// Calling method should check if completed (true) or not (false) to decide if updating their view of that item
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 => 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,
params: {'id': contact.id},
),
child: const Text('Posts')),
ElevatedButton(
onPressed: () async =>
await openProfileExternal(context, contact),
child: const Text('Open In Browser'),
),
],
),
const VerticalPadding(),
HtmlWidget(
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.updateNotifications());
}
}