|
| 1 | +// Copyright 2023, the Chromium project authors. Please see the AUTHORS file |
| 2 | +// for details. All rights reserved. Use of this source code is governed by a |
| 3 | +// BSD-style license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +import 'package:firebase_storage/firebase_storage.dart'; |
| 6 | +import 'package:firebase_ui_storage/firebase_ui_storage.dart'; |
| 7 | +import 'package:flutter/widgets.dart'; |
| 8 | + |
| 9 | +import 'default_loading_indicator.dart'; |
| 10 | + |
| 11 | +Widget _defaultLoadingBuilder(BuildContext context) { |
| 12 | + return const DefaultLoadingIndicator(); |
| 13 | +} |
| 14 | + |
| 15 | +class StorageGridView extends StatefulWidget { |
| 16 | + /// The [Reference] to list items from. |
| 17 | + /// If not provided, a [loadingController] must be created and passed. |
| 18 | + final Reference? ref; |
| 19 | + |
| 20 | + final PaginatedLoadingController? loadingController; |
| 21 | + |
| 22 | + /// The number of items to load per page. |
| 23 | + /// Defaults to 50. |
| 24 | + final int pageSize; |
| 25 | + |
| 26 | + /// A builder that is called for the first page load. |
| 27 | + final Widget Function(BuildContext context) loadingBuilder; |
| 28 | + |
| 29 | + /// A builder that is called when an error occurs during page loading. |
| 30 | + final Widget Function( |
| 31 | + BuildContext context, |
| 32 | + Object? error, |
| 33 | + PaginatedLoadingController controller, |
| 34 | + )? errorBuilder; |
| 35 | + |
| 36 | + /// A builder that is called for each item in the list. |
| 37 | + final Widget Function(BuildContext context, Reference ref) itemBuilder; |
| 38 | + |
| 39 | + /// See [SliverGridDelegate]. |
| 40 | + final SliverGridDelegate gridDelegate; |
| 41 | + |
| 42 | + const StorageGridView({ |
| 43 | + super.key, |
| 44 | + this.ref, |
| 45 | + this.loadingController, |
| 46 | + this.pageSize = 50, |
| 47 | + this.loadingBuilder = _defaultLoadingBuilder, |
| 48 | + this.errorBuilder, |
| 49 | + this.gridDelegate = const SliverGridDelegateWithFixedCrossAxisCount( |
| 50 | + crossAxisCount: 3, |
| 51 | + ), |
| 52 | + required this.itemBuilder, |
| 53 | + }) : assert( |
| 54 | + ref != null || loadingController != null, |
| 55 | + 'ref or loadingController must be provided', |
| 56 | + ); |
| 57 | + |
| 58 | + @override |
| 59 | + State<StorageGridView> createState() => _StorageGridViewState(); |
| 60 | +} |
| 61 | + |
| 62 | +class _StorageGridViewState extends State<StorageGridView> { |
| 63 | + late PaginatedLoadingController ctrl = widget.loadingController ?? |
| 64 | + PaginatedLoadingController( |
| 65 | + ref: widget.ref!, |
| 66 | + pageSize: widget.pageSize, |
| 67 | + ); |
| 68 | + |
| 69 | + Widget gridBuilder(BuildContext context, List<Reference> items) { |
| 70 | + return GridView.builder( |
| 71 | + gridDelegate: widget.gridDelegate, |
| 72 | + itemCount: items.length, |
| 73 | + itemBuilder: (context, index) { |
| 74 | + if (ctrl.shouldLoadNextPage(index)) { |
| 75 | + ctrl.load(); |
| 76 | + } |
| 77 | + |
| 78 | + return widget.itemBuilder(context, items[index]); |
| 79 | + }, |
| 80 | + ); |
| 81 | + } |
| 82 | + |
| 83 | + @override |
| 84 | + Widget build(BuildContext context) { |
| 85 | + return AnimatedBuilder( |
| 86 | + animation: ctrl, |
| 87 | + builder: (context, _) { |
| 88 | + return switch (ctrl.state) { |
| 89 | + InitialPageLoading() => widget.loadingBuilder(context), |
| 90 | + PageLoadError( |
| 91 | + error: final error, |
| 92 | + items: final items, |
| 93 | + ) => |
| 94 | + widget.errorBuilder != null |
| 95 | + ? widget.errorBuilder!(context, error, ctrl) |
| 96 | + : gridBuilder(context, items ?? []), |
| 97 | + PageLoading(items: final items) => gridBuilder(context, items), |
| 98 | + PageLoadComplete(items: final items) => gridBuilder(context, items), |
| 99 | + }; |
| 100 | + }, |
| 101 | + ); |
| 102 | + } |
| 103 | +} |
0 commit comments