✨ Able to manage publisher actor
This commit is contained in:
@@ -255,6 +255,24 @@
|
||||
"walletCurrencyShortGolds": "NSD",
|
||||
"retry": "Retry",
|
||||
"creatorHubUnselectedHint": "Pick / create a publisher to get started.",
|
||||
"publisherFediverse": "Fediverse Actor",
|
||||
"publisherFediverseDescription": "Configure your publisher's ActivityPub actor for federated social networking",
|
||||
"publisherFediverseEnabled": "Enabled",
|
||||
"publisherFediverseDisabled": "Disabled",
|
||||
"publisherFediverseNotConfigured": "Not configured",
|
||||
"publisherFediverseEnableHint": "Enable your publisher to interact with fediverse",
|
||||
"publisherFediverseDisableHint": "Disable your publisher's fediverse actor",
|
||||
"publisherFediverseEnableConfirm": "Enable fediverse actor?",
|
||||
"publisherFediverseDisableConfirm": "Disable fediverse actor?",
|
||||
"publisherFediverseEnabledSuccess": "Fediverse actor enabled successfully",
|
||||
"publisherFediverseDisabledSuccess": "Fediverse actor disabled successfully",
|
||||
"publisherFediverseFailedToEnable": "Failed to enable fediverse actor",
|
||||
"publisherFediverseFailedToDisable": "Failed to disable fediverse actor",
|
||||
"publisherFediverseWhatIs": "What is Fediverse?",
|
||||
"publisherFediverseAbout": "The fediverse is a federated network of social platforms. Enabling this feature allows your publisher to interact with users across different ActivityPub-compatible services like Mastodon, PeerTube, and more.",
|
||||
"publisherFediverseActorUri": "Actor URI",
|
||||
"publisherFediverseFollowerCount": "Followers",
|
||||
"publisherFediverseNoFollowers": "No followers yet",
|
||||
"relationships": "Relationships",
|
||||
"addFriend": "Send a Friend Request",
|
||||
"addFriendShort": "Add as Friend",
|
||||
|
||||
@@ -212,7 +212,7 @@ final class AccountAppbarForcegroundColorProvider
|
||||
}
|
||||
|
||||
String _$accountAppbarForcegroundColorHash() =>
|
||||
r'127fcc7fd6ec6a41ac4a6975276b5271aa4fa7d0';
|
||||
r'59e0049a5158ea653f0afd724df9ff2312b90050';
|
||||
|
||||
final class AccountAppbarForcegroundColorFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/activitypub.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/models/publisher.dart';
|
||||
import 'package:island/models/heatmap.dart';
|
||||
@@ -15,6 +16,7 @@ import 'package:island/screens/creators/publishers_form.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/utils/text.dart';
|
||||
import 'package:island/widgets/account/account_picker.dart';
|
||||
import 'package:island/widgets/activitypub/actor_profile.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
@@ -78,6 +80,19 @@ Future<List<SnPublisherMember>> publisherInvites(Ref ref) async {
|
||||
.toList();
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<SnActorStatusResponse> publisherActorStatus(
|
||||
Ref ref,
|
||||
String? publisherName,
|
||||
) async {
|
||||
if (publisherName == null) throw Exception('Publisher name is required');
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
final response = await apiClient.get(
|
||||
'/sphere/publishers/$publisherName/fediverse',
|
||||
);
|
||||
return SnActorStatusResponse.fromJson(response.data);
|
||||
}
|
||||
|
||||
final publisherMemberListNotifierProvider = AsyncNotifierProvider.family
|
||||
.autoDispose(PublisherMemberListNotifier.new);
|
||||
|
||||
@@ -501,6 +516,24 @@ class CreatorHubScreen extends HookConsumerWidget {
|
||||
leading: const Icon(Symbols.edit),
|
||||
onTap: updatePublisher,
|
||||
),
|
||||
ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
minTileHeight: 48,
|
||||
title: Text('publisherFediverse').tr(),
|
||||
trailing: Icon(Symbols.chevron_right),
|
||||
leading: const Icon(Symbols.public),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (context) => _PublisherFediverseSheet(
|
||||
publisherUname: currentPublisher.value!.name,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
@@ -1126,3 +1159,152 @@ class _PublisherInviteSheet extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PublisherFediverseSheet extends HookConsumerWidget {
|
||||
final String publisherUname;
|
||||
|
||||
const _PublisherFediverseSheet({required this.publisherUname});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final actorStatus = ref.watch(publisherActorStatusProvider(publisherUname));
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final isLoading = useState(false);
|
||||
|
||||
Future<void> toggleActor() async {
|
||||
final currentStatus = actorStatus.value;
|
||||
if (currentStatus == null) return;
|
||||
|
||||
final confirm = await showConfirmAlert(
|
||||
currentStatus.enabled
|
||||
? 'publisherFediverseDisableConfirm'.tr()
|
||||
: 'publisherFediverseEnableConfirm'.tr(),
|
||||
currentStatus.enabled
|
||||
? 'publisherFediverseDisabled'.tr()
|
||||
: 'publisherFediverseEnabled'.tr(),
|
||||
isDanger: !currentStatus.enabled,
|
||||
);
|
||||
if (confirm != true) return;
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
if (currentStatus.enabled) {
|
||||
await apiClient.delete(
|
||||
'/sphere/publishers/$publisherUname/fediverse',
|
||||
);
|
||||
} else {
|
||||
await apiClient.post('/sphere/publishers/$publisherUname/fediverse');
|
||||
}
|
||||
ref.invalidate(publisherActorStatusProvider(publisherUname));
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return SheetScaffold(
|
||||
titleText: 'publisherFediverse'.tr(),
|
||||
child: actorStatus.when(
|
||||
data: (status) => SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Column(
|
||||
spacing: 16,
|
||||
children: [
|
||||
Card.outlined(
|
||||
child: SwitchListTile(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
value: status.enabled,
|
||||
onChanged: isLoading.value ? null : (_) => toggleActor(),
|
||||
title: Text(
|
||||
status.enabled
|
||||
? 'publisherFediverseEnabled'.tr()
|
||||
: 'publisherFediverseDisabled'.tr(),
|
||||
),
|
||||
subtitle: Text(
|
||||
status.enabled
|
||||
? 'publisherFediverseDisableHint'.tr()
|
||||
: 'publisherFediverseEnableHint'.tr(),
|
||||
),
|
||||
secondary: isLoading.value
|
||||
? const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: Icon(
|
||||
status.enabled
|
||||
? Icons.check_circle
|
||||
: Icons.circle_outlined,
|
||||
color: status.enabled ? Colors.green : Colors.grey,
|
||||
),
|
||||
),
|
||||
).padding(horizontal: 16),
|
||||
if (status.enabled) ...[
|
||||
if (status.actor != null) ...[
|
||||
ListTile(
|
||||
leading: ActorPictureWidget(
|
||||
actor: status.actor!,
|
||||
radius: 24,
|
||||
),
|
||||
title: Text(
|
||||
status.actor!.displayName ??
|
||||
status.actor!.username ??
|
||||
'unknown'.tr(),
|
||||
),
|
||||
subtitle: Text(
|
||||
'@${status.actor!.username}@${status.actor!.instance.domain}',
|
||||
),
|
||||
isThreeLine: true,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 28),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.link),
|
||||
title: Text('publisherFediverseActorUri').tr(),
|
||||
subtitle: Text(status.actorUri ?? 'N/A'),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
),
|
||||
],
|
||||
ListTile(
|
||||
leading: const Icon(Symbols.group),
|
||||
title: Text('publisherFediverseFollowerCount').tr(),
|
||||
subtitle: Text(
|
||||
status.followerCount > 0
|
||||
? status.followerCount.toString()
|
||||
: 'publisherFediverseNoFollowers'.tr(),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
),
|
||||
],
|
||||
ExpansionTile(
|
||||
leading: const Icon(Symbols.info),
|
||||
title: Text('publisherFediverseWhatIs').tr(),
|
||||
tilePadding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16,
|
||||
horizontal: 32,
|
||||
),
|
||||
child: Text('publisherFediverseAbout').tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, _) => ResponseErrorWidget(
|
||||
error: error,
|
||||
onRetry: () =>
|
||||
ref.invalidate(publisherActorStatusProvider(publisherUname)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,3 +354,81 @@ final class PublisherInvitesProvider
|
||||
}
|
||||
|
||||
String _$publisherInvitesHash() => r'93aafc2f02af0a7a055ec1770b3999363dfaabdc';
|
||||
|
||||
@ProviderFor(publisherActorStatus)
|
||||
const publisherActorStatusProvider = PublisherActorStatusFamily._();
|
||||
|
||||
final class PublisherActorStatusProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SnActorStatusResponse>,
|
||||
SnActorStatusResponse,
|
||||
FutureOr<SnActorStatusResponse>
|
||||
>
|
||||
with
|
||||
$FutureModifier<SnActorStatusResponse>,
|
||||
$FutureProvider<SnActorStatusResponse> {
|
||||
const PublisherActorStatusProvider._({
|
||||
required PublisherActorStatusFamily super.from,
|
||||
required String? super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'publisherActorStatusProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$publisherActorStatusHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'publisherActorStatusProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SnActorStatusResponse> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SnActorStatusResponse> create(Ref ref) {
|
||||
final argument = this.argument as String?;
|
||||
return publisherActorStatus(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PublisherActorStatusProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$publisherActorStatusHash() =>
|
||||
r'406117cb99b2aef236945ef0ef59e857d8835029';
|
||||
|
||||
final class PublisherActorStatusFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SnActorStatusResponse>, String?> {
|
||||
const PublisherActorStatusFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'publisherActorStatusProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
PublisherActorStatusProvider call(String? publisherName) =>
|
||||
PublisherActorStatusProvider._(argument: publisherName, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'publisherActorStatusProvider';
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ final class PublisherAppbarForcegroundColorProvider
|
||||
}
|
||||
|
||||
String _$publisherAppbarForcegroundColorHash() =>
|
||||
r'cd9a9816177a6eecc2bc354acebbbd48892ffdd7';
|
||||
r'a7c9795c68a29beb611d2c258022c9a5640f2061';
|
||||
|
||||
final class PublisherAppbarForcegroundColorFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
|
||||
|
||||
@@ -70,4 +70,21 @@ class ActivityPubService {
|
||||
.toList();
|
||||
return users;
|
||||
}
|
||||
|
||||
Future<SnActorStatusResponse> getPublisherActorStatus(
|
||||
String publisherName,
|
||||
) async {
|
||||
final response = await _client.get(
|
||||
'/sphere/publishers/$publisherName/fediverse',
|
||||
);
|
||||
return SnActorStatusResponse.fromJson(response.data);
|
||||
}
|
||||
|
||||
Future<void> enablePublisherActor(String publisherName) async {
|
||||
await _client.post('/sphere/publishers/$publisherName/fediverse');
|
||||
}
|
||||
|
||||
Future<void> disablePublisherActor(String publisherName) async {
|
||||
await _client.delete('/sphere/publishers/$publisherName/fediverse');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user