Add loading indicators to top and followed streams

This commit is contained in:
Tommy Chow 2022-01-02 21:49:37 -05:00
parent 132a2c8348
commit 8102ea6185
7 changed files with 89 additions and 13 deletions

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/screens/stream_list/stream_card.dart';
import 'package:frosty/screens/stream_list/streams_followed/followed_streams_store.dart';
import 'package:frosty/widgets/loading_indicator.dart';
class FollowedStreams extends StatelessWidget {
final FollowedStreamsStore store;
@ -14,6 +15,11 @@ class FollowedStreams extends StatelessWidget {
onRefresh: store.refresh,
child: Observer(
builder: (_) {
if (store.followedStreams.isEmpty && store.isLoading) {
return const LoadingIndicator(
subtitle: Text('Loading followed streams...'),
);
}
return ListView.builder(
itemCount: store.followedStreams.length,
itemBuilder: (context, index) {

View file

@ -9,11 +9,11 @@ class FollowedStreamsStore = _FollowedStreamsStoreBase with _$FollowedStreamsSto
abstract class _FollowedStreamsStoreBase with Store {
/// The list of the fetched followed streams.
@observable
@readonly
var _followedStreams = ObservableList<StreamTwitch>();
ObservableList<StreamTwitch> get followedStreams => _followedStreams;
/// The loading status for pagination.
@readonly
bool _isLoading = false;
/// The pagination cursor for followed streams.
@ -34,12 +34,15 @@ abstract class _FollowedStreamsStoreBase with Store {
Future<void> getFollowedStreams() async {
_isLoading = true;
final newFollowedStreams =
await Twitch.getFollowedStreams(id: authStore.user.details!.id, headers: authStore.headersTwitch, cursor: _followedStreamsCurrentCursor);
final newFollowedStreams = await Twitch.getFollowedStreams(
id: authStore.user.details!.id,
headers: authStore.headersTwitch,
cursor: _followedStreamsCurrentCursor,
);
if (newFollowedStreams != null) {
if (_followedStreamsCurrentCursor == null) {
_followedStreams = ObservableList.of(newFollowedStreams.data);
_followedStreams = newFollowedStreams.data.asObservable();
} else {
_followedStreams.addAll(newFollowedStreams.data);
}

View file

@ -12,12 +12,14 @@ mixin _$FollowedStreamsStore on _FollowedStreamsStoreBase, Store {
final _$_followedStreamsAtom =
Atom(name: '_FollowedStreamsStoreBase._followedStreams');
@override
ObservableList<StreamTwitch> get _followedStreams {
ObservableList<StreamTwitch> get followedStreams {
_$_followedStreamsAtom.reportRead();
return super._followedStreams;
}
@override
ObservableList<StreamTwitch> get _followedStreams => followedStreams;
@override
set _followedStreams(ObservableList<StreamTwitch> value) {
_$_followedStreamsAtom.reportWrite(value, super._followedStreams, () {
@ -25,6 +27,23 @@ mixin _$FollowedStreamsStore on _FollowedStreamsStoreBase, Store {
});
}
final _$_isLoadingAtom = Atom(name: '_FollowedStreamsStoreBase._isLoading');
bool get isLoading {
_$_isLoadingAtom.reportRead();
return super._isLoading;
}
@override
bool get _isLoading => isLoading;
@override
set _isLoading(bool value) {
_$_isLoadingAtom.reportWrite(value, super._isLoading, () {
super._isLoading = value;
});
}
final _$getFollowedStreamsAsyncAction =
AsyncAction('_FollowedStreamsStoreBase.getFollowedStreams');

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/screens/stream_list/stream_card.dart';
import 'package:frosty/screens/stream_list/streams_top/top_streams_store.dart';
import 'package:frosty/widgets/loading_indicator.dart';
class TopStreams extends StatelessWidget {
final TopStreamsStore store;
@ -14,6 +15,9 @@ class TopStreams extends StatelessWidget {
onRefresh: store.refresh,
child: Observer(
builder: (_) {
if (store.topStreams.isEmpty && store.isLoading) {
return const LoadingIndicator(subtitle: Text('Loading top streams...'));
}
return ListView.builder(
itemCount: store.topStreams.length,
itemBuilder: (context, index) {

View file

@ -9,11 +9,11 @@ class TopStreamsStore = _TopStreamsStoreBase with _$TopStreamsStore;
abstract class _TopStreamsStoreBase with Store {
/// The list of the fetched top streams.
@observable
@readonly
var _topStreams = ObservableList<StreamTwitch>();
ObservableList<StreamTwitch> get topStreams => _topStreams;
/// The loading status for pagination.
@readonly
bool _isLoading = false;
/// The pagination cursor for top streams.
@ -34,11 +34,14 @@ abstract class _TopStreamsStoreBase with Store {
Future<void> getTopStreams() async {
_isLoading = true;
final newTopStreams = await Twitch.getTopStreams(headers: authStore.headersTwitch, cursor: _topStreamsCurrentCursor);
final newTopStreams = await Twitch.getTopStreams(
headers: authStore.headersTwitch,
cursor: _topStreamsCurrentCursor,
);
if (newTopStreams != null) {
if (_topStreamsCurrentCursor == null) {
_topStreams = ObservableList.of(newTopStreams.data);
_topStreams = newTopStreams.data.asObservable();
} else {
_topStreams.addAll(newTopStreams.data);
}

View file

@ -11,12 +11,14 @@ part of 'top_streams_store.dart';
mixin _$TopStreamsStore on _TopStreamsStoreBase, Store {
final _$_topStreamsAtom = Atom(name: '_TopStreamsStoreBase._topStreams');
@override
ObservableList<StreamTwitch> get _topStreams {
ObservableList<StreamTwitch> get topStreams {
_$_topStreamsAtom.reportRead();
return super._topStreams;
}
@override
ObservableList<StreamTwitch> get _topStreams => topStreams;
@override
set _topStreams(ObservableList<StreamTwitch> value) {
_$_topStreamsAtom.reportWrite(value, super._topStreams, () {
@ -24,6 +26,23 @@ mixin _$TopStreamsStore on _TopStreamsStoreBase, Store {
});
}
final _$_isLoadingAtom = Atom(name: '_TopStreamsStoreBase._isLoading');
bool get isLoading {
_$_isLoadingAtom.reportRead();
return super._isLoading;
}
@override
bool get _isLoading => isLoading;
@override
set _isLoading(bool value) {
_$_isLoadingAtom.reportWrite(value, super._isLoading, () {
super._isLoading = value;
});
}
final _$getTopStreamsAsyncAction =
AsyncAction('_TopStreamsStoreBase.getTopStreams');

View file

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
class LoadingIndicator extends StatelessWidget {
final Widget? subtitle;
final double spacing;
const LoadingIndicator({Key? key, this.subtitle, this.spacing = 10.0}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircularProgressIndicator.adaptive(),
SizedBox(height: spacing),
if (subtitle != null) subtitle!,
],
),
);
}
}