Add filter to subscription-list
This commit is contained in:
@@ -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 {
|
class APIClient {
|
||||||
static const String _base = 'https://simplecloudnotifier.de';
|
static const String _base = 'https://simplecloudnotifier.de';
|
||||||
static const String _prefix = '/api/v2';
|
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(
|
return await _request(
|
||||||
name: 'getSubscriptionList',
|
name: 'getSubscriptionList',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
relURL: 'users/${auth.getUserID()}/subscriptions',
|
relURL: 'users/${auth.getUserID()}/subscriptions',
|
||||||
query: {
|
query: {
|
||||||
'direction': ['both'],
|
'direction': [filter.direction],
|
||||||
'confirmation': ['all'],
|
'confirmation': [filter.confirmation],
|
||||||
'external': ['all'],
|
'external': [filter.external],
|
||||||
},
|
},
|
||||||
fn: (json) => Subscription.fromJsonArray(json['subscriptions'] as List<dynamic>),
|
fn: (json) => Subscription.fromJsonArray(json['subscriptions'] as List<dynamic>),
|
||||||
authToken: auth.getToken(),
|
authToken: auth.getToken(),
|
||||||
|
|||||||
47
flutter/lib/components/filter_chips/filter_chips.dart
Normal file
47
flutter/lib/components/filter_chips/filter_chips.dart
Normal 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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,7 +117,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
|
|||||||
|
|
||||||
_futureSubscriptionCount = ImmediateFuture.ofFuture(() async {
|
_futureSubscriptionCount = ImmediateFuture.ofFuture(() async {
|
||||||
if (!userAcc.isAuth()) throw new Exception('not logged in');
|
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;
|
return subs.length;
|
||||||
}());
|
}());
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
|
|||||||
// refresh all data and then replace teh futures used in build()
|
// refresh all data and then replace teh futures used in build()
|
||||||
|
|
||||||
final channelsAll = await APIClient.getChannelList(userAcc, ChannelSelector.all);
|
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 clients = await APIClient.getClientList(userAcc);
|
||||||
final keys = await APIClient.getKeyTokenList(userAcc);
|
final keys = await APIClient.getKeyTokenList(userAcc);
|
||||||
final senderNames = await APIClient.getSenderNameList(userAcc);
|
final senderNames = await APIClient.getSenderNameList(userAcc);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:simplecloudnotifier/api/api_client.dart';
|
import 'package:simplecloudnotifier/api/api_client.dart';
|
||||||
import 'package:simplecloudnotifier/components/badge_display/badge_display.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/components/layout/scaffold.dart';
|
||||||
import 'package:simplecloudnotifier/models/channel.dart';
|
import 'package:simplecloudnotifier/models/channel.dart';
|
||||||
import 'package:simplecloudnotifier/models/subscription.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/pages/subscription_list/subscription_list_item.dart';
|
||||||
import 'package:simplecloudnotifier/state/scn_data_cache.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 {
|
class SubscriptionListPage extends StatefulWidget {
|
||||||
const SubscriptionListPage({super.key});
|
const SubscriptionListPage({super.key});
|
||||||
|
|
||||||
@@ -26,6 +50,8 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
|
|||||||
final userCache = Map<String, UserPreview>();
|
final userCache = Map<String, UserPreview>();
|
||||||
final channelCache = Map<String, ChannelPreview>();
|
final channelCache = Map<String, ChannelPreview>();
|
||||||
|
|
||||||
|
SubscriptionListFilter filter = SubscriptionListFilter.ALL;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -60,7 +86,7 @@ class _SubscriptionListPageState extends State<SubscriptionListPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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));
|
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),
|
extraPadding: EdgeInsets.fromLTRB(0, 0, 0, 16),
|
||||||
hidden: !AppSettings().showInfoAlerts,
|
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(
|
Expanded(
|
||||||
child: _buildList(context),
|
child: _buildList(context),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user