Skip to content

Commit

Permalink
feat(ui_storage): add StorageListView and PaginatedLoadingController (#…
Browse files Browse the repository at this point in the history
…11170)

* feat(ui_storage): add StorageListView and PaginatedLoadingController

* drop uuid

* license header
  • Loading branch information
lesnitsky committed Jun 30, 2023
1 parent 1e4783d commit dcf1b22
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 3 deletions.
33 changes: 33 additions & 0 deletions packages/firebase_ui_storage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,36 @@ class MyUploadProgress extends StatelessWidget {
}
}
```

### StorageListView

```dart
StorageListView(
ref: storage.ref('images'),
itemBuilder: (context, ref) {
return AspectRatio(
aspectRatio: 1,
child: StorageImage(ref: ref),
);
},
loadingBuilder: (context) {
return const Center(
child: CircularProgressIndicator(),
);
},
errorBuilder: (context, error, controller) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Error: $error'),
TextButton(
onPressed: () => controller.load(),
child: const Text('Retry'),
),
],
),
);
},
);
```
2 changes: 2 additions & 0 deletions packages/firebase_ui_storage/example/lib/src/apps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter/material.dart';

import 'progress_bar_app.dart';
import 'upload_button_app.dart';
import 'list_view_app.dart';

abstract class App implements Widget {
String get name;
Expand All @@ -17,6 +18,7 @@ const apps = <App>[
UploadButtonApp(),
ProgressBarApp(),
StorageImageApp(),
StorageListViewApp(),
];

class AppList extends StatelessWidget {
Expand Down
40 changes: 40 additions & 0 deletions packages/firebase_ui_storage/example/lib/src/list_view_app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2023, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:firebase_storage/firebase_storage.dart';
import 'package:firebase_ui_storage/firebase_ui_storage.dart';
import 'package:flutter/material.dart';

import 'apps.dart';

class StorageListViewApp extends StatelessWidget implements App {
const StorageListViewApp({super.key});

@override
String get name => 'StorageListView';

@override
Widget build(BuildContext context) {
return StorageListView(
ref: FirebaseStorage.instance.ref('list'),
itemBuilder: (context, ref) {
return ListTile(
title: FutureBuilder(
future: ref.getData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
if (snapshot.hasData) {
return Text(snapshot.data.toString());
}

return const Text('Loading...');
},
),
);
},
);
}
}
2 changes: 1 addition & 1 deletion packages/firebase_ui_storage/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ publish_to: 'none'
version: 0.1.0

environment:
sdk: '>=2.19.5 <4.0.0'
sdk: '>=3.0.0 <4.0.0'

dependencies:
cupertino_icons: ^1.0.3
Expand Down
2 changes: 2 additions & 0 deletions packages/firebase_ui_storage/lib/firebase_ui_storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ export 'src/widgets/progress_indicator.dart'
show TaskProgressIndicator, TaskProgressWidget, ErrorBuilder;

export 'src/widgets/image.dart' show StorageImage, LoadingStateVariant;
export 'src/paginated_loading_controller.dart';
export 'src/widgets/list_view.dart';
104 changes: 104 additions & 0 deletions packages/firebase_ui_storage/lib/src/paginated_loading_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2023, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/foundation.dart';

/// A base class for loading states.
sealed class PaginatedLoadingState {
const PaginatedLoadingState();
}

/// Indicates that the first page is loading.
class InitialPageLoading extends PaginatedLoadingState {
const InitialPageLoading();
}

class PageLoading extends PaginatedLoadingState {
final List<Reference> items;

const PageLoading({required this.items});
}

class PageLoadComplete extends PaginatedLoadingState {
final List<Reference> pageItems;
final List<Reference> items;

const PageLoadComplete({
required this.pageItems,
required this.items,
});
}

class PageLoadError extends PaginatedLoadingState {
final Object? error;
final List<Reference>? items;

const PageLoadError({
required this.error,
this.items,
});
}

class PaginatedLoadingController extends ChangeNotifier {
int pageSize;
final Reference ref;

PaginatedLoadingController({
required this.ref,
this.pageSize = 50,
}) {
load();
}

PaginatedLoadingState? _state;
PaginatedLoadingState get state => _state!;

ListResult? _cursor;
List<Reference>? _items;

ListOptions get _listOptions {
return ListOptions(
maxResults: pageSize,
pageToken: _cursor?.nextPageToken,
);
}

Future<void> load() {
_state = _state == null
? const InitialPageLoading()
: PageLoading(items: _items!);

notifyListeners();

return ref.list(_listOptions).then((value) {
_cursor = value;
(_items ??= []).addAll(value.items);

_state = PageLoadComplete(
pageItems: value.items,
items: _items!,
);

notifyListeners();
}).catchError((e) {
_state = PageLoadError(
error: e,
items: _items,
);

notifyListeners();
});
}

bool shouldLoadNextPage(int itemIndex) {
return switch (state) {
InitialPageLoading() => false,
PageLoading() => false,
PageLoadComplete(items: final items) =>
itemIndex == (items.length - pageSize + 1),
PageLoadError() => false,
};
}
}

0 comments on commit dcf1b22

Please sign in to comment.