Add filter to subscription-list

This commit is contained in:
2025-11-09 22:51:37 +01:00
parent febc0a8f43
commit 1aadd9c368
4 changed files with 110 additions and 7 deletions

View File

@@ -54,6 +54,20 @@ class MessageFilter {
});
}
class SubscriptionFilter {
static final SubscriptionFilter ALL = SubscriptionFilter('both', 'all', 'all');
static final SubscriptionFilter OWNED_INACTIVE = SubscriptionFilter('outgoing', 'unconfirmed', 'false');
static final SubscriptionFilter OWNED_ACTIVE = SubscriptionFilter('outgoing', 'confirmed', 'false');
static final SubscriptionFilter EXTERNAL_ALL = SubscriptionFilter('outgoing', 'all', 'true');
static final SubscriptionFilter INCOMING_ALL = SubscriptionFilter('incoming', 'all', 'true');
final String direction; // 'outgoing' | 'incoming' | 'both'
final String confirmation; // 'confirmed' | 'unconfirmed' | 'all'
final String external; // 'true' | 'false' | 'all'
SubscriptionFilter(this.direction, this.confirmation, this.external) {}
}
class APIClient {
static const String _base = 'https://simplecloudnotifier.de';
static const String _prefix = '/api/v2';
@@ -345,15 +359,15 @@ class APIClient {
);
}
static Future<List<Subscription>> getSubscriptionList(TokenSource auth) async {
static Future<List<Subscription>> getSubscriptionList(TokenSource auth, SubscriptionFilter filter) async {
return await _request(
name: 'getSubscriptionList',
method: 'GET',
relURL: 'users/${auth.getUserID()}/subscriptions',
query: {
'direction': ['both'],
'confirmation': ['all'],
'external': ['all'],
'direction': [filter.direction],
'confirmation': [filter.confirmation],
'external': [filter.external],
},
fn: (json) => Subscription.fromJsonArray(json['subscriptions'] as List<dynamic>),
authToken: auth.getToken(),

View File

@@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
class FilterChips<T extends Enum> extends StatelessWidget {
final List<(T, String)> options;
final T value;
final void Function(T)? onChanged;
const FilterChips({
Key? key,
required this.options,
required this.value,
required this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
for (var opt in options) _buildChiplet(context, opt.$1, opt.$2),
],
),
);
}
Widget _buildChiplet(BuildContext context, T optValue, String optText) {
final isSelected = optValue == value;
return Padding(
padding: const EdgeInsets.fromLTRB(0, 2, 4, 2),
child: InputChip(
label: Text(
optText,
style: isSelected ? TextStyle(color: Theme.of(context).colorScheme.onPrimary) : null,
),
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
isEnabled: true,
selected: true,
showCheckmark: false,
onPressed: () {
if (!isSelected) onChanged?.call(optValue);
},
selectedColor: isSelected ? Theme.of(context).colorScheme.primary : null,
),
);
}
}

View File

@@ -117,7 +117,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
_futureSubscriptionCount = ImmediateFuture.ofFuture(() async {
if (!userAcc.isAuth()) throw new Exception('not logged in');
final subs = await APIClient.getSubscriptionList(userAcc);
final subs = await APIClient.getSubscriptionList(userAcc, SubscriptionFilter.ALL);
return subs.length;
}());
@@ -153,7 +153,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
// refresh all data and then replace teh futures used in build()
final channelsAll = await APIClient.getChannelList(userAcc, ChannelSelector.all);
final subs = await APIClient.getSubscriptionList(userAcc);
final subs = await APIClient.getSubscriptionList(userAcc, SubscriptionFilter.ALL);
final clients = await APIClient.getClientList(userAcc);
final keys = await APIClient.getKeyTokenList(userAcc);
final senderNames = await APIClient.getSenderNameList(userAcc);

View File

@@ -3,6 +3,7 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:provider/provider.dart';
import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/components/badge_display/badge_display.dart';
import 'package:simplecloudnotifier/components/filter_chips/filter_chips.dart';
import 'package:simplecloudnotifier/components/layout/scaffold.dart';
import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/subscription.dart';
@@ -13,6 +14,29 @@ import 'package:simplecloudnotifier/state/app_auth.dart';
import 'package:simplecloudnotifier/pages/subscription_list/subscription_list_item.dart';
import 'package:simplecloudnotifier/state/scn_data_cache.dart';
enum SubscriptionListFilter {
ALL,
INACTIVE,
OWN,
EXTERNAL,
INCOMING;
SubscriptionFilter toAPIFilter() {
switch (this) {
case ALL:
return SubscriptionFilter.ALL;
case INACTIVE:
return SubscriptionFilter.OWNED_INACTIVE;
case OWN:
return SubscriptionFilter.OWNED_ACTIVE;
case EXTERNAL:
return SubscriptionFilter.EXTERNAL_ALL;
case INCOMING:
return SubscriptionFilter.INCOMING_ALL;
}
}
}
class SubscriptionListPage extends StatefulWidget {
const SubscriptionListPage({super.key});
@@ -26,6 +50,8 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
final userCache = Map<String, UserPreview>();
final channelCache = Map<String, ChannelPreview>();
SubscriptionListFilter filter = SubscriptionListFilter.ALL;
@override
void initState() {
super.initState();
@@ -60,7 +86,7 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
}
try {
final items = (await APIClient.getSubscriptionList(acc)).toList();
final items = (await APIClient.getSubscriptionList(acc, filter.toAPIFilter())).toList();
items.sort((a, b) => -1 * a.timestampCreated.compareTo(b.timestampCreated));
@@ -106,6 +132,22 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
extraPadding: EdgeInsets.fromLTRB(0, 0, 0, 16),
hidden: !AppSettings().showInfoAlerts,
),
FilterChips<SubscriptionListFilter>(
options: [
(SubscriptionListFilter.ALL, 'All'),
(SubscriptionListFilter.OWN, 'Own'),
(SubscriptionListFilter.EXTERNAL, 'External'),
(SubscriptionListFilter.INCOMING, 'Incoming'),
(SubscriptionListFilter.INACTIVE, 'Inactive'),
],
value: filter,
onChanged: (newFilter) {
setState(() {
filter = newFilter;
_pagingController.refresh();
});
},
),
Expanded(
child: _buildList(context),
)