import 'package:flutter/material.dart'; import 'package:hiddify/core/core_providers.dart'; import 'package:hiddify/domain/failures.dart'; import 'package:hiddify/features/common/common.dart'; import 'package:hiddify/features/proxies/notifier/notifier.dart'; import 'package:hiddify/features/proxies/widgets/widgets.dart'; import 'package:hiddify/utils/utils.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:recase/recase.dart'; class ProxiesPage extends HookConsumerWidget with PresLogger { const ProxiesPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final t = ref.watch(translationsProvider); final asyncProxies = ref.watch(proxiesNotifierProvider); final notifier = ref.watch(proxiesNotifierProvider.notifier); final sortBy = ref.watch(proxiesSortProvider); final selectActiveProxyMutation = useMutation( initialOnFailure: (error) => CustomToast.error(t.printError(error)).show(context), ); switch (asyncProxies) { case AsyncData(value: final groups): if (groups.isEmpty) { return Scaffold( body: CustomScrollView( slivers: [ NestedTabAppBar( title: Text(t.proxies.pageTitle.titleCase), ), SliverFillRemaining( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(t.proxies.emptyProxiesMsg.titleCase), ], ), ), ], ), ); } final group = groups.first; return Scaffold( body: CustomScrollView( slivers: [ NestedTabAppBar( title: Text(t.proxies.pageTitle.titleCase), actions: [ PopupMenuButton( initialValue: sortBy, onSelected: ref.read(proxiesSortProvider.notifier).update, icon: const Icon(Icons.sort), tooltip: t.proxies.sortTooltip, itemBuilder: (context) { return [ ...ProxiesSort.values.map( (e) => PopupMenuItem( value: e, child: Text(e.present(t)), ), ), ]; }, ), ], ), SliverLayoutBuilder( builder: (context, constraints) { final width = constraints.crossAxisExtent; if (!PlatformUtils.isDesktop && width < 648) { return SliverPadding( padding: const EdgeInsets.only(bottom: 86), sliver: SliverList.builder( itemBuilder: (_, index) { final proxy = group.items[index]; return ProxyTile( proxy, selected: group.selected == proxy.tag, onSelect: () async { if (selectActiveProxyMutation .state.isInProgress) { return; } selectActiveProxyMutation.setFuture( notifier.changeProxy(group.tag, proxy.tag), ); }, ); }, itemCount: group.items.length, ), ); } return SliverGrid.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: (width / 268).floor(), mainAxisExtent: 68, ), itemBuilder: (context, index) { final proxy = group.items[index]; return ProxyTile( proxy, selected: group.selected == proxy.tag, onSelect: () async { if (selectActiveProxyMutation.state.isInProgress) { return; } selectActiveProxyMutation.setFuture( notifier.changeProxy( group.tag, proxy.tag, ), ); }, ); }, itemCount: group.items.length, ); }, ), ], ), floatingActionButton: FloatingActionButton( onPressed: () async => notifier.urlTest(group.tag), tooltip: t.proxies.delayTestTooltip.titleCase, child: const Icon(Icons.bolt), ), ); case AsyncError(:final error): return Scaffold( body: CustomScrollView( slivers: [ NestedTabAppBar( title: Text(t.proxies.pageTitle.titleCase), ), SliverErrorBodyPlaceholder( t.printError(error), icon: null, ), ], ), ); case AsyncLoading(): return Scaffold( body: CustomScrollView( slivers: [ NestedTabAppBar( title: Text(t.proxies.pageTitle.titleCase), ), const SliverLoadingBodyPlaceholder(), ], ), ); // TODO: remove default: return const Scaffold(); } } }