Skip to content

Commit

Permalink
Merge branch 'release/1.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
rhalff committed Oct 21, 2019
2 parents 4a89b28 + cc3c6b6 commit 9695a98
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 69 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.2.0
- Improve feed scrolling and reload

## 1.0.2
- Add logout to drawer
- Fix permissions
Expand Down
3 changes: 2 additions & 1 deletion lib/pages/articles/about.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:realworld_flutter/localizations/rw_localizations.dart';
import 'package:realworld_flutter/version.dart';
import 'package:realworld_flutter/widgets/external_link.dart';

void about(BuildContext context) {
Expand All @@ -20,7 +21,7 @@ void about(BuildContext context) {
),
*
*/
applicationVersion: 'Version: 1.0.0',
applicationVersion: 'Version: $version',
applicationLegalese: '© ${DateTime.now().year} ${locale.appName}',
children: <Widget>[
Padding(
Expand Down
33 changes: 23 additions & 10 deletions lib/pages/articles/feed.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:realworld_flutter/blocs/articles/bloc.dart';
import 'package:realworld_flutter/pages/articles/preview_post.dart';
Expand All @@ -12,34 +13,43 @@ class Feed extends StatefulWidget {
final Function(ArticlesBloc bloc) onLoad;
final Function(ArticlesBloc bloc) onLoadMore;
final double scrollThreshold;

/// The ScrollController itself is handled by the NestedScrollView parent.
final ScrollController scrollController;
Feed({
@required this.id,
@required this.label,
@required this.onRefresh,
@required this.onLoad,
@required this.onLoadMore,
@required this.scrollController,
this.scrollThreshold = 400.0,
});
@override
_FeedState createState() => _FeedState();
}

class _FeedState extends State<Feed> {
final _scrollController = ScrollController();
double _scrollMarker = 0;
ArticlesBloc _articlesBloc;

@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
widget.scrollController.addListener(_onScroll);
_articlesBloc = BlocProvider.of<ArticlesBloc>(context);

if (_articlesBloc.currentState is! ArticlesLoaded) {
widget.onLoad(_articlesBloc);
}
}

@override
void dispose() {
widget.scrollController.removeListener(_onScroll);
super.dispose();
}

@override
Widget build(BuildContext context) {
return BlocBuilder<ArticlesBloc, ArticlesState>(
Expand All @@ -60,7 +70,6 @@ class _FeedState extends State<Feed> {
return RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
final article = articles[index];

Expand Down Expand Up @@ -94,18 +103,22 @@ class _FeedState extends State<Feed> {
);
}

@override
void dispose() {
_scrollController.dispose();
super.dispose();
bool get _hasReachedMax {
return (_articlesBloc.currentState as ArticlesLoaded).hasReachedMax;
}

bool get _isAtBottom {
final scrollPosition = widget.scrollController.position;

return scrollPosition.atEdge &&
scrollPosition.userScrollDirection == ScrollDirection.forward;
}

void _onScroll() {
final maxScroll = _scrollMarker + widget.scrollThreshold;
final currentScroll = _scrollController.position.pixels;
final currentScroll = widget.scrollController.position.pixels;
if (_articlesBloc.currentState is ArticlesLoaded) {
if (!(_articlesBloc.currentState as ArticlesLoaded).hasReachedMax &&
currentScroll >= maxScroll) {
if (!_hasReachedMax && (currentScroll >= maxScroll || _isAtBottom)) {
_scrollMarker = maxScroll;
widget.onLoadMore(_articlesBloc);
}
Expand Down
131 changes: 74 additions & 57 deletions lib/pages/articles/feeds.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,28 @@ class _FeedsState extends State<Feeds> with SingleTickerProviderStateMixin {

final Map<String, ArticlesBloc> _blocs = {};

ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();

final initialIndex = widget.initialFeed != null
? widget.feeds
.indexWhere((FeedModel feed) => feed.id == widget.initialFeed)
: 0;

super.initState();
_tabController = TabController(
length: widget.feeds.length,
initialIndex: initialIndex == -1 ? 0 : initialIndex,
vsync: this,
);

super.initState();
}

@override
void dispose() {
_scrollController.dispose();
_tabController.dispose();
for (var cachedBloc in _blocs.values) {
cachedBloc.dispose();
Expand All @@ -62,67 +67,79 @@ class _FeedsState extends State<Feeds> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverPersistentHeader(
pinned: widget.pinned,
delegate: HeroHeader(
minExtent: widget.minExtentHeader,
maxExtent: widget.maxExtentHeader,
child: widget.header,
),
controller: _scrollController,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverPersistentHeader(
pinned: widget.pinned,
delegate: HeroHeader(
minExtent: widget.minExtentHeader,
maxExtent: widget.maxExtentHeader,
child: widget.header,
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Container(
child: TabBar(
controller: _tabController,
tabs: widget.feeds
.map((feed) => Tab(text: feed.label))
.toList(),
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Container(
child: TabBar(
controller: _tabController,
tabs: widget.feeds
.map((feed) => Tab(text: feed.label))
.toList(),
),
),
),
];
},
body: SizedBox(
height: 300,
child: AnimatedBuilder(
animation: _tabController.animation,
builder: (BuildContext context, snapshot) {
return TabBarView(
controller: _tabController,
children: mapWithIndex(
widget.feeds,
(FeedModel feed, int index) {
if (feed.child != null) {
return feed.child;
} else {
return BlocProvider<ArticlesBloc>.value(
value: getArticlesBloc(feed),
child: Opacity(
opacity: index % 2 == 0
? 1 - _tabController.animation.value
: _tabController.animation.value,
child: Feed(
id: feed.id,
scrollThreshold: feed.scrollThreshold,
label: feed.label,
onRefresh: feed.onRefresh,
onLoadMore: feed.onLoadMore,
onLoad: feed.onLoad,
),
),
);
}
},
),
);
},
),
));
];
},
body: Builder(
builder: (BuildContext context) {
final innerScrollController =
context.ancestorWidgetOfExactType(PrimaryScrollController)
as PrimaryScrollController;

return SizedBox(
height: 300,
child: AnimatedBuilder(
animation: _tabController.animation,
builder: (BuildContext context, snapshot) {
return TabBarView(
controller: _tabController,
children: mapWithIndex(
widget.feeds,
(FeedModel feed, int index) {
if (feed.child != null) {
return feed.child;
} else {
return BlocProvider<ArticlesBloc>.value(
value: getArticlesBloc(feed),
child: Opacity(
opacity: index % 2 == 0
? 1 - _tabController.animation.value
: _tabController.animation.value,
child: Feed(
id: feed.id,
scrollThreshold: feed.scrollThreshold,
label: feed.label,
onRefresh: feed.onRefresh,
onLoadMore: feed.onLoadMore,
onLoad: feed.onLoad,
scrollController:
innerScrollController.controller,
),
),
);
}
},
),
);
},
),
);
},
),
);
}

ArticlesBloc getArticlesBloc(FeedModel feed) {
Expand Down
1 change: 1 addition & 0 deletions lib/version.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
final version = '1.1.0';
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: realworld_flutter
description: A Realworld Flutter Application

version: 1.0.2
version: 1.1.0

environment:
sdk: ">=2.2.2 <3.0.0"
Expand Down

0 comments on commit 9695a98

Please sign in to comment.