Implement proper handling for inactive/active subscriptions

This commit is contained in:
2025-04-18 00:11:01 +02:00
parent a43a3b441f
commit 63bc71c405
10 changed files with 268 additions and 48 deletions

View File

@@ -9,10 +9,12 @@ import 'package:simplecloudnotifier/models/scan_result.dart';
import 'package:simplecloudnotifier/models/subscription.dart';
import 'package:simplecloudnotifier/models/user.dart';
import 'package:simplecloudnotifier/pages/channel_message_view/channel_message_view.dart';
import 'package:simplecloudnotifier/pages/filtered_message_view/filtered_message_view.dart';
import 'package:simplecloudnotifier/state/app_auth.dart';
import 'package:simplecloudnotifier/state/app_bar_state.dart';
import 'package:simplecloudnotifier/state/application_log.dart';
import 'package:simplecloudnotifier/types/immediate_future.dart';
import 'package:simplecloudnotifier/utils/dialogs.dart';
import 'package:simplecloudnotifier/utils/navi.dart';
import 'package:simplecloudnotifier/utils/toaster.dart';
import 'package:simplecloudnotifier/utils/ui.dart';
@@ -196,7 +198,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (own)',
values: [_formatSubscriptionStatus(this.subscription)],
iconActions: isSubscribed ? [(FontAwesomeIcons.solidSquareXmark, _unsubscribe)] : [(FontAwesomeIcons.solidSquareRss, _subscribe)],
iconActions: isSubscribed ? [(FontAwesomeIcons.solidSquareXmark, null, _unsubscribe)] : [(FontAwesomeIcons.solidSquareRss, null, _subscribe)],
),
_buildForeignSubscriptions(context),
_buildOwnerCard(context, true),
@@ -217,7 +219,48 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
}
Widget _buildForeignChannelView(BuildContext context, ChannelPreview channel) {
final isSubscribed = (subscription != null && subscription!.confirmed);
Widget subCard;
if (subscription != null && subscription!.confirmed && subscription!.active) {
subCard = UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (foreign)',
values: [_formatSubscriptionStatus(subscription)],
iconActions: [(FontAwesomeIcons.solidSquareXmark, null, _deactivate)],
);
} else if (subscription != null && subscription!.confirmed && !subscription!.active) {
subCard = UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (foreign)',
values: [_formatSubscriptionStatus(subscription)],
iconActions: [(FontAwesomeIcons.solidSquareXmark, Colors.red[900], () => _unsubscribe(confirm: 'Really (permantenly) delete your subscription to this channel?')), (FontAwesomeIcons.solidSquareRss, null, _activate)],
);
} else if (subscription != null && !subscription!.confirmed) {
subCard = UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (foreign)',
values: [_formatSubscriptionStatus(subscription)],
iconActions: [(FontAwesomeIcons.solidSquareXmark, Colors.red[900], () => _unsubscribe(confirm: 'Really withdraw your subscription-request to this channel?'))],
);
} else if (subscription == null) {
subCard = UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (foreign)',
values: [_formatSubscriptionStatus(subscription)],
iconActions: [(FontAwesomeIcons.solidSquareRss, null, _subscribe)],
);
} else {
subCard = UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (foreign)',
values: [_formatSubscriptionStatus(subscription)],
);
}
return SingleChildScrollView(
child: Padding(
@@ -240,15 +283,16 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
),
_buildDisplayNameCard(context, false),
_buildDescriptionNameCard(context, false),
UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidDiagramSubtask,
title: 'Subscription (foreign)',
values: [_formatSubscriptionStatus(subscription)],
iconActions: isSubscribed ? [(FontAwesomeIcons.solidSquareXmark, _unsubscribe)] : [(FontAwesomeIcons.solidSquareRss, _subscribe)],
),
subCard,
_buildForeignSubscriptions(context),
_buildOwnerCard(context, false),
UI.metaCard(
context: context,
icon: FontAwesomeIcons.solidEnvelope,
title: 'Messages',
values: [channel.messagesSent.toString()],
mainAction: (subscription != null && subscription!.confirmed) ? () => Navi.push(context, () => FilteredMessageViewPage(title: channel.displayName, filter: MessageFilter(channelIDs: [channel.channelID]))) : null,
),
],
),
),
@@ -269,7 +313,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
icon: FontAwesomeIcons.solidDiagramSuccessor,
title: 'Subscription (' + (user?.username ?? user?.userID ?? 'other') + ')',
values: [_formatSubscriptionStatus(sub)],
iconActions: _getForeignSubActions(sub),
iconActions: _getForeignIncomingSubActions(sub),
),
],
);
@@ -371,7 +415,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
icon: FontAwesomeIcons.solidInputText,
title: 'DisplayName',
values: [_displayNameOverride ?? channelPreview!.displayName],
iconActions: isOwned ? [(FontAwesomeIcons.penToSquare, _showEditDisplayName)] : [],
iconActions: isOwned ? [(FontAwesomeIcons.penToSquare, null, _showEditDisplayName)] : [],
);
} else if (_editDisplayName == EditState.saving) {
return Padding(
@@ -427,7 +471,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
icon: FontAwesomeIcons.solidInputPipe,
title: 'Description',
values: [_descriptionNameOverride ?? channelPreview?.descriptionName ?? ''],
iconActions: isOwned ? [(FontAwesomeIcons.penToSquare, _showEditDescriptionName)] : [],
iconActions: isOwned ? [(FontAwesomeIcons.penToSquare, null, _showEditDescriptionName)] : [],
);
} else if (_editDescriptionName == EditState.saving) {
return Padding(
@@ -536,11 +580,16 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
}
}
void _unsubscribe() async {
void _unsubscribe({String? confirm = null}) async {
final acc = AppAuth();
if (subscription == null) return;
if (confirm != null) {
final r = await UIDialogs.showConfirmDialog(context, confirm, okText: 'Unsubscribe', cancelText: 'Cancel');
if (!r) return;
}
try {
await APIClient.deleteSubscription(acc, widget.channelID, subscription!.subscriptionID);
widget.needsReload?.call();
@@ -554,6 +603,42 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
}
}
void _deactivate() async {
final acc = AppAuth();
if (subscription == null) return;
try {
await APIClient.deactivateSubscription(acc, widget.channelID, subscription!.subscriptionID);
widget.needsReload?.call();
await _initStateAsync(false);
Toaster.success("Success", 'Unsubscribed from channel');
} catch (exc, trace) {
Toaster.error("Error", 'Failed to unsubscribe from channel');
ApplicationLog.error('Failed to unsubscribe from channel: ' + exc.toString(), trace: trace);
}
}
void _activate() async {
final acc = AppAuth();
if (subscription == null) return;
try {
await APIClient.activateSubscription(acc, widget.channelID, subscription!.subscriptionID);
widget.needsReload?.call();
await _initStateAsync(false);
Toaster.success("Success", 'Subscribed to channel');
} catch (exc, trace) {
Toaster.error("Error", 'Failed to subscribe to channel');
ApplicationLog.error('Failed to subscribe to channel: ' + exc.toString(), trace: trace);
}
}
void _cancelForeignSubscription(Subscription sub) async {
final acc = AppAuth();
@@ -605,10 +690,14 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
String _formatSubscriptionStatus(Subscription? subscription) {
if (subscription == null) {
return 'Not Subscribed';
} else if (subscription.confirmed) {
return 'Subscribed';
} else {
} else if (subscription.confirmed && subscription.active) {
return 'Subscribed & Active';
} else if (subscription.confirmed && !subscription.active) {
return 'Subscribed & Inactive';
} else if (!subscription.confirmed) {
return 'Requested';
} else {
return '?';
}
}
@@ -662,13 +751,13 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
}
}
List<(IconData, void Function())> _getForeignSubActions(Subscription sub) {
List<(IconData, Color?, void Function())> _getForeignIncomingSubActions(Subscription sub) {
if (sub.confirmed) {
return [(FontAwesomeIcons.solidSquareXmark, () => _cancelForeignSubscription(sub))];
return [(FontAwesomeIcons.solidSquareXmark, Colors.red[900], () => _cancelForeignSubscription(sub))];
} else {
return [
(FontAwesomeIcons.solidSquareCheck, () => _confirmForeignSubscription(sub)),
(FontAwesomeIcons.solidSquareXmark, () => _denyForeignSubscription(sub)),
(FontAwesomeIcons.solidSquareCheck, Colors.green[900], () => _confirmForeignSubscription(sub)),
(FontAwesomeIcons.solidSquareXmark, Colors.red[900], () => _denyForeignSubscription(sub)),
];
}
}