better feed fetching
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -46,34 +47,6 @@ class CompletePageInfo extends _$CompletePageInfo {
|
||||
return AsyncData(cached);
|
||||
}
|
||||
|
||||
// ref.listen(
|
||||
// fireImmediately: true,
|
||||
// pageInfoProvider(cached.url, isImageRequest: false),
|
||||
// (previous, next) {
|
||||
// if (next.hasValue) {
|
||||
// final current = stateOrNull?.value ?? cached;
|
||||
|
||||
// state = AsyncData(
|
||||
// current.copyWith(
|
||||
// //Cached is preferred as this comes from gecko and is more likely to be correct compared to manual request
|
||||
// favicon: current.favicon ?? next.value!.favicon,
|
||||
// feeds: current.feeds ?? next.value!.feeds,
|
||||
// title: current.title.whenNotEmpty ?? next.value!.title,
|
||||
// ),
|
||||
// );
|
||||
// } else {
|
||||
// state = next;
|
||||
// }
|
||||
// },
|
||||
// onError: (error, stackTrace) {
|
||||
// logger.e(
|
||||
// 'Error listening to pageInfoProvider',
|
||||
// error: error,
|
||||
// stackTrace: stackTrace,
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
|
||||
ref.listen(
|
||||
fireImmediately: true,
|
||||
tabStateProvider(cached.id).select((value) => value?.title),
|
||||
@@ -150,3 +123,19 @@ Future<WebPageInfo> pageInfo(
|
||||
|
||||
return result.value;
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
AsyncValue<EquatableValue<Set<Uri>?>> websiteFeedProvider(
|
||||
Ref ref,
|
||||
String tabId,
|
||||
) {
|
||||
final tabState = ref.watch(tabStateProvider(tabId))!;
|
||||
final feeds = ref.watch(
|
||||
pageInfoProvider(
|
||||
tabState.url,
|
||||
isImageRequest: false,
|
||||
).select((value) => value.whenData((data) => EquatableValue(data.feeds))),
|
||||
);
|
||||
|
||||
return feeds;
|
||||
}
|
||||
|
||||
@@ -189,3 +189,92 @@ final class PageInfoFamily extends $Family
|
||||
@override
|
||||
String toString() => r'pageInfoProvider';
|
||||
}
|
||||
|
||||
@ProviderFor(websiteFeedProvider)
|
||||
const websiteFeedProviderProvider = WebsiteFeedProviderFamily._();
|
||||
|
||||
final class WebsiteFeedProviderProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<EquatableValue<Set<Uri>?>>,
|
||||
AsyncValue<EquatableValue<Set<Uri>?>>,
|
||||
AsyncValue<EquatableValue<Set<Uri>?>>
|
||||
>
|
||||
with $Provider<AsyncValue<EquatableValue<Set<Uri>?>>> {
|
||||
const WebsiteFeedProviderProvider._({
|
||||
required WebsiteFeedProviderFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'websiteFeedProviderProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$websiteFeedProviderHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'websiteFeedProviderProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<AsyncValue<EquatableValue<Set<Uri>?>>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
AsyncValue<EquatableValue<Set<Uri>?>> create(Ref ref) {
|
||||
final argument = this.argument as String;
|
||||
return websiteFeedProvider(ref, argument);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(AsyncValue<EquatableValue<Set<Uri>?>> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride:
|
||||
$SyncValueProvider<AsyncValue<EquatableValue<Set<Uri>?>>>(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is WebsiteFeedProviderProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$websiteFeedProviderHash() =>
|
||||
r'b8ad81b883acee41f420af9aeca254fbd29b3107';
|
||||
|
||||
final class WebsiteFeedProviderFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
AsyncValue<EquatableValue<Set<Uri>?>>,
|
||||
String
|
||||
> {
|
||||
const WebsiteFeedProviderFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'websiteFeedProviderProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
WebsiteFeedProviderProvider call(String tabId) =>
|
||||
WebsiteFeedProviderProvider._(argument: tabId, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'websiteFeedProviderProvider';
|
||||
}
|
||||
|
||||
+20
-21
@@ -24,47 +24,47 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:weblibre/core/routing/routes.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
|
||||
import 'package:weblibre/presentation/controllers/website_title.dart';
|
||||
import 'package:weblibre/presentation/widgets/rounded_text.dart';
|
||||
|
||||
class WebsiteFeedTile extends HookConsumerWidget {
|
||||
final TabState initialTabState;
|
||||
class WebsiteFeedMenuButton extends HookConsumerWidget {
|
||||
final String tabId;
|
||||
|
||||
const WebsiteFeedTile(this.initialTabState, {super.key});
|
||||
const WebsiteFeedMenuButton(this.tabId, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final pageInfoAsync = ref.watch(completePageInfoProvider(initialTabState));
|
||||
final feedsAsync = ref.watch(websiteFeedProviderProvider(tabId));
|
||||
|
||||
return Skeletonizer(
|
||||
enabled: pageInfoAsync.isLoading && initialTabState.feeds == null,
|
||||
child: pageInfoAsync.when(
|
||||
enabled: feedsAsync.isLoading && feedsAsync.value?.value == null,
|
||||
child: feedsAsync.when(
|
||||
skipLoadingOnReload: true,
|
||||
data: (info) {
|
||||
if (info.feeds.isEmpty) {
|
||||
data: (feeds) {
|
||||
if (feeds.value.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.rss_feed),
|
||||
title: const Text('Available Web Feeds'),
|
||||
trailing: RoundedBackground(
|
||||
return MenuItemButton(
|
||||
leadingIcon: const Icon(Icons.rss_feed),
|
||||
closeOnActivate: false,
|
||||
trailingIcon: RoundedBackground(
|
||||
child: Text(
|
||||
info.feeds!.length.toString(),
|
||||
feeds.value!.length.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
onPressed: () async {
|
||||
await SelectFeedDialogRoute(
|
||||
feedsJson: jsonEncode(
|
||||
info.feeds!.map((feed) => feed.toString()).toList(),
|
||||
feeds.value!.map((feed) => feed.toString()).toList(),
|
||||
),
|
||||
).push(context);
|
||||
},
|
||||
child: const Text('Available Web Feeds'),
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) {
|
||||
@@ -77,11 +77,10 @@ class WebsiteFeedTile extends HookConsumerWidget {
|
||||
// onRetry: () => ref.refresh(pageInfoProvider(url)),
|
||||
// );
|
||||
},
|
||||
loading: () => const ListTile(
|
||||
leading: Icon(Icons.rss_feed),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: Text('Available Web Feeds'),
|
||||
trailing: Bone.icon(),
|
||||
loading: () => const MenuItemButton(
|
||||
leadingIcon: Icon(Icons.rss_feed),
|
||||
trailingIcon: Bone.icon(),
|
||||
child: Text('Available Web Feeds'),
|
||||
),
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user