✨ Able to manage publisher actor
This commit is contained in:
@@ -255,6 +255,24 @@
|
|||||||
"walletCurrencyShortGolds": "NSD",
|
"walletCurrencyShortGolds": "NSD",
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
"creatorHubUnselectedHint": "Pick / create a publisher to get started.",
|
"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",
|
"relationships": "Relationships",
|
||||||
"addFriend": "Send a Friend Request",
|
"addFriend": "Send a Friend Request",
|
||||||
"addFriendShort": "Add as Friend",
|
"addFriendShort": "Add as Friend",
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ final class AccountAppbarForcegroundColorProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$accountAppbarForcegroundColorHash() =>
|
String _$accountAppbarForcegroundColorHash() =>
|
||||||
r'127fcc7fd6ec6a41ac4a6975276b5271aa4fa7d0';
|
r'59e0049a5158ea653f0afd724df9ff2312b90050';
|
||||||
|
|
||||||
final class AccountAppbarForcegroundColorFamily extends $Family
|
final class AccountAppbarForcegroundColorFamily extends $Family
|
||||||
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
|
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:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/activitypub.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
import 'package:island/models/publisher.dart';
|
import 'package:island/models/publisher.dart';
|
||||||
import 'package:island/models/heatmap.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/services/responsive.dart';
|
||||||
import 'package:island/utils/text.dart';
|
import 'package:island/utils/text.dart';
|
||||||
import 'package:island/widgets/account/account_picker.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/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
@@ -78,6 +80,19 @@ Future<List<SnPublisherMember>> publisherInvites(Ref ref) async {
|
|||||||
.toList();
|
.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
|
final publisherMemberListNotifierProvider = AsyncNotifierProvider.family
|
||||||
.autoDispose(PublisherMemberListNotifier.new);
|
.autoDispose(PublisherMemberListNotifier.new);
|
||||||
|
|
||||||
@@ -501,6 +516,24 @@ class CreatorHubScreen extends HookConsumerWidget {
|
|||||||
leading: const Icon(Symbols.edit),
|
leading: const Icon(Symbols.edit),
|
||||||
onTap: updatePublisher,
|
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(
|
ListTile(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
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';
|
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() =>
|
String _$publisherAppbarForcegroundColorHash() =>
|
||||||
r'cd9a9816177a6eecc2bc354acebbbd48892ffdd7';
|
r'a7c9795c68a29beb611d2c258022c9a5640f2061';
|
||||||
|
|
||||||
final class PublisherAppbarForcegroundColorFamily extends $Family
|
final class PublisherAppbarForcegroundColorFamily extends $Family
|
||||||
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
|
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
|
||||||
|
|||||||
@@ -70,4 +70,21 @@ class ActivityPubService {
|
|||||||
.toList();
|
.toList();
|
||||||
return users;
|
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