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

@@ -145,11 +145,11 @@ class _ChannelListExtendedPageState extends State<ChannelListExtendedPage> with
),
),
floatingActionButton: FloatingActionButton(
heroTag: 'fab_channel_list_qr',
heroTag: 'fab_channel_list_extended-plus',
onPressed: () {
Navi.push(context, () => ChannelScannerPage());
},
child: const Icon(FontAwesomeIcons.qrcode),
child: const Icon(FontAwesomeIcons.plus),
),
);
}

View File

@@ -138,32 +138,68 @@ class _ChannelListItemState extends State<ChannelListItem> {
}
Widget _buildIcon(BuildContext context) {
if (widget.subscription == null) {
Widget result = Icon(FontAwesomeIcons.solidSquareDashed, color: Theme.of(context).colorScheme.outline, size: 32); // not-subscribed
final acc = AppAuth();
if (widget.subscription == null && widget.channel.ownerUserID == acc.userID) {
// not-subscribed (own channel)
Widget result = Icon(FontAwesomeIcons.solidSquareRss, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3), size: 32);
result = GestureDetector(onTap: () => _subscribe(), child: result);
return result;
} else if (widget.subscription!.confirmed && widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
Widget result = Icon(FontAwesomeIcons.solidSquareRss, color: Theme.of(context).colorScheme.onPrimaryContainer, size: 32); // subscribed (own channel)
result = GestureDetector(onTap: () => _unsubscribe(widget.subscription!), child: result);
return result;
} else if (widget.subscription!.confirmed) {
Widget result = Icon(FontAwesomeIcons.solidSquareShareNodes, color: Theme.of(context).colorScheme.onPrimaryContainer, size: 32); // subscribed (foreign channel)
result = GestureDetector(onTap: () => _unsubscribe(widget.subscription!), child: result);
return result;
} else {
Widget result = Icon(FontAwesomeIcons.solidSquareEnvelope, color: Theme.of(context).colorScheme.tertiary, size: 32); // requested
result = GestureDetector(onTap: () => _unsubscribe(widget.subscription!), child: result);
} else if (widget.subscription == null) {
// not-subscribed (foreign channel)
Widget result = Icon(FontAwesomeIcons.solidSquareShareNodes, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3), size: 32);
return result;
} else if (widget.subscription!.confirmed && !widget.subscription!.active) {
if (widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
// inactive (own channel)
Widget result = Icon(FontAwesomeIcons.solidSquareRss, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3), size: 32);
result = GestureDetector(onTap: () => _activate(widget.subscription!), child: result);
return result;
} else {
// inactive (foreign channel)
Widget result = Icon(FontAwesomeIcons.solidSquareShareNodes, color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3), size: 32);
result = GestureDetector(onTap: () => _activate(widget.subscription!), child: result);
return result;
}
} else if (widget.subscription!.confirmed && widget.subscription!.active) {
if (widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
// subscribed+active (own channel)
Widget result = Icon(FontAwesomeIcons.solidSquareRss, color: Theme.of(context).colorScheme.onPrimaryContainer, size: 32);
result = GestureDetector(onTap: () => _unsubscribe(widget.subscription!), child: result);
return result;
} else {
// subscribed+active (foreign channel)
Widget result = Icon(FontAwesomeIcons.solidSquareShareNodes, color: Theme.of(context).colorScheme.onPrimaryContainer, size: 32);
result = GestureDetector(onTap: () => _deactivate(widget.subscription!), child: result);
return result;
}
} else if (!widget.subscription!.confirmed) {
if (widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
// requested (own channel)
return SizedBox(width: 32, height: 32);
} else {
// requested (foreign channel)
Widget result = Icon(FontAwesomeIcons.solidSquareEnvelope, color: Theme.of(context).colorScheme.tertiary, size: 32);
result = GestureDetector(onTap: () => _unsubscribe(widget.subscription!), child: result);
return result;
}
}
// fallback
return SizedBox(width: 32, height: 32);
}
Widget _buildSubscriptionStateText(BuildContext context) {
if (widget.subscription == null) {
return Text("", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
} else if (widget.subscription!.confirmed && widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
} else if (widget.subscription!.confirmed && widget.subscription!.active && widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
return Text("subscribed", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
} else if (widget.subscription!.confirmed) {
return Text("subscripted (foreign channe)", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
} else if (widget.subscription!.confirmed && !widget.subscription!.active && widget.channel.ownerUserID == widget.subscription!.subscriberUserID) {
return Text("inactive (own channel)", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
} else if (widget.subscription!.confirmed && widget.subscription!.active) {
return Text("subscribed & active (foreign channel)", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
} else if (widget.subscription!.confirmed && !widget.subscription!.active) {
return Text("subscribed (foreign channel) (inactive)", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
} else {
return Text("subscription requested", style: TextStyle(color: Theme.of(context).textTheme.bodyLarge?.color?.withAlpha(160)));
}
@@ -194,12 +230,12 @@ class _ChannelListItemState extends State<ChannelListItem> {
void _unsubscribe(Subscription sub) async {
final acc = AppAuth();
if (acc.isAuth() && widget.channel.ownerUserID == acc.getUserID() && widget.subscription != null) {
if (acc.isAuth()) {
try {
await APIClient.deleteSubscription(acc, widget.channel.channelID, widget.subscription!.subscriptionID);
await APIClient.deleteSubscription(acc, sub.channelID, sub.subscriptionID);
widget.onChannelListReloadTrigger.call();
widget.onSubscriptionChanged.call(widget.channel.channelID, null);
widget.onSubscriptionChanged.call(sub.channelID, null);
Toaster.success("Success", 'Unsubscribed from channel');
} catch (exc, trace) {
@@ -208,4 +244,40 @@ class _ChannelListItemState extends State<ChannelListItem> {
}
}
}
void _deactivate(Subscription sub) async {
final acc = AppAuth();
if (acc.isAuth()) {
try {
var newSub = await APIClient.deactivateSubscription(acc, sub.channelID, sub.subscriptionID);
widget.onChannelListReloadTrigger.call();
widget.onSubscriptionChanged.call(sub.channelID, newSub);
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(Subscription sub) async {
final acc = AppAuth();
if (acc.isAuth()) {
try {
var newSub = await APIClient.activateSubscription(acc, sub.channelID, sub.subscriptionID);
widget.onChannelListReloadTrigger.call();
widget.onSubscriptionChanged.call(sub.channelID, newSub);
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);
}
}
}
}