kopia lustrzana https://gitlab.com/mysocialportal/relatica
296 wiersze
8.9 KiB
Dart
296 wiersze
8.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.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 '../models/auth/profile.dart';
|
|
import '../models/connection.dart';
|
|
import '../models/exec_error.dart';
|
|
import '../riverpod_controllers/account_services.dart';
|
|
import '../riverpod_controllers/connection_manager_services.dart';
|
|
import '../riverpod_controllers/feature_checker_services.dart';
|
|
import '../riverpod_controllers/follow_requests_services.dart';
|
|
import '../riverpod_controllers/networking/network_status_services.dart';
|
|
import '../riverpod_controllers/notification_services.dart';
|
|
import '../routes.dart';
|
|
import '../utils/url_opening_utils.dart';
|
|
|
|
class FollowRequestAdjudicationScreen extends ConsumerStatefulWidget {
|
|
final String userId;
|
|
|
|
const FollowRequestAdjudicationScreen({super.key, required this.userId});
|
|
|
|
@override
|
|
ConsumerState<FollowRequestAdjudicationScreen> createState() =>
|
|
_FollowRequestAdjudicationScreenState();
|
|
}
|
|
|
|
class _FollowRequestAdjudicationScreenState
|
|
extends ConsumerState<FollowRequestAdjudicationScreen> {
|
|
var processing = false;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final profile = ref.watch(activeProfileProvider);
|
|
final loading = ref.watch(followRequestsLoadingProvider(profile)) ||
|
|
ref.watch(connectionsLoadingProvider(profile));
|
|
late final Result<Connection, ExecError> result;
|
|
if (ref.read(featureCheckProvider(
|
|
profile, RelaticaFeatures.usingActualFollowRequests))) {
|
|
result = ref
|
|
.watch(followRequestByIdProvider(profile, widget.userId))
|
|
.mapValue((request) => request.connection);
|
|
} else {
|
|
result = ref.watch(connectionByIdProvider(
|
|
profile,
|
|
widget.userId,
|
|
forceUpdate: true,
|
|
));
|
|
}
|
|
|
|
late final Widget body;
|
|
if (result.isFailure) {
|
|
if (result.error.type == ErrorType.notFound && loading) {
|
|
ref.read(followRequestsProvider(profile).notifier).update();
|
|
body = const Text('Loading...');
|
|
} else {
|
|
body = Text('Error getting request info: ${result.error}');
|
|
}
|
|
} else {
|
|
final contact = result.value;
|
|
final contactStatus = ref
|
|
.watch(
|
|
connectionByIdProvider(
|
|
profile,
|
|
contact.id,
|
|
forceUpdate: true,
|
|
),
|
|
)
|
|
.transform((c) => c.status)
|
|
.getValueOrElse(() => ConnectionStatus.unknown);
|
|
|
|
switch (contactStatus) {
|
|
case ConnectionStatus.theyFollowYou:
|
|
case ConnectionStatus.youFollowThem:
|
|
case ConnectionStatus.unknown:
|
|
case ConnectionStatus.none:
|
|
body = _buildMainPanel(context, contact, profile);
|
|
break;
|
|
case ConnectionStatus.mutual:
|
|
body = const Text('Already allowed them to connect');
|
|
break;
|
|
case ConnectionStatus.you:
|
|
body = Text(loading
|
|
? '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(
|
|
'User is blocked. Unblock to accept connection request.',
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text(
|
|
'Accept Request?',
|
|
),
|
|
leading: processing
|
|
? const IconButton(onPressed: null, icon: Icon(Icons.arrow_back))
|
|
: null,
|
|
),
|
|
body: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Center(child: body),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildMainPanel(
|
|
BuildContext context,
|
|
Connection contact,
|
|
Profile profile,
|
|
) {
|
|
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(profile, contact, true),
|
|
child: const Text('Accept and follow back'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: processing
|
|
? null
|
|
: () async => accept(profile, contact, false),
|
|
child: const Text("Accept but don't follow back"),
|
|
),
|
|
ElevatedButton(
|
|
onPressed:
|
|
processing ? null : () async => reject(profile, contact),
|
|
child: const Text('Reject'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed:
|
|
processing ? null : () async => ignore(profile, contact),
|
|
child: const Text('Ignore (Rejects but user cannot ask again)'),
|
|
),
|
|
],
|
|
),
|
|
const VerticalPadding(),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
ElevatedButton(
|
|
onPressed: processing
|
|
? null
|
|
: () => context.pushNamed(
|
|
ScreenPaths.userPosts,
|
|
pathParameters: {'id': contact.id},
|
|
),
|
|
child: const Text('Posts')),
|
|
ElevatedButton(
|
|
onPressed: processing
|
|
? null
|
|
: () 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(
|
|
Profile profile,
|
|
Connection contact,
|
|
bool followBack,
|
|
) async {
|
|
setState(() {
|
|
processing = true;
|
|
});
|
|
|
|
await ref
|
|
.read(connectionModifierProvider(profile, contact).notifier)
|
|
.acceptFollowRequest();
|
|
if (followBack) {
|
|
ref
|
|
.read(notificationsManagerProvider(profile).notifier)
|
|
.refreshNotifications();
|
|
await ref
|
|
.read(connectionModifierProvider(profile, contact).notifier)
|
|
.follow();
|
|
}
|
|
|
|
_performUpdates(profile);
|
|
|
|
setState(() {
|
|
processing = false;
|
|
});
|
|
|
|
if (mounted) {
|
|
ref
|
|
.read(notificationsManagerProvider(profile).notifier)
|
|
.refreshNotifications();
|
|
context
|
|
.goNamed(ScreenPaths.userProfile, pathParameters: {'id': contact.id});
|
|
}
|
|
}
|
|
|
|
Future<void> reject(
|
|
Profile profile,
|
|
Connection contact,
|
|
) async {
|
|
setState(() {
|
|
processing = true;
|
|
});
|
|
|
|
await ref
|
|
.read(connectionModifierProvider(profile, contact).notifier)
|
|
.rejectFollowRequest();
|
|
|
|
_performUpdates(profile);
|
|
setState(() {
|
|
processing = false;
|
|
});
|
|
|
|
if (mounted && context.canPop()) {
|
|
ref
|
|
.read(notificationsManagerProvider(profile).notifier)
|
|
.refreshConnectionRequestNotifications();
|
|
context.pop();
|
|
}
|
|
}
|
|
|
|
Future<void> ignore(
|
|
Profile profile,
|
|
Connection contact,
|
|
) async {
|
|
setState(() {
|
|
processing = true;
|
|
});
|
|
|
|
await ref
|
|
.read(connectionModifierProvider(profile, contact).notifier)
|
|
.ignoreFollowRequest();
|
|
_performUpdates(profile);
|
|
|
|
setState(() {
|
|
processing = false;
|
|
});
|
|
|
|
if (mounted && context.canPop()) {
|
|
ref
|
|
.read(notificationsManagerProvider(profile).notifier)
|
|
.refreshConnectionRequestNotifications();
|
|
context.pop();
|
|
}
|
|
}
|
|
|
|
void _performUpdates(Profile profile) {
|
|
ref.read(followRequestsProvider(profile).notifier).update();
|
|
ref
|
|
.read(notificationsManagerProvider(profile).notifier)
|
|
.refreshNotifications();
|
|
}
|
|
}
|