-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1b187ac
commit 7c29af9
Showing
10 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_rearch/flutter_rearch.dart'; | ||
import 'package:rearch/rearch.dart'; | ||
|
||
void main() => runApp(const MyApp()); | ||
|
||
/// A factory capsule that returns the input data after a brief delay. | ||
/// This also doubles as an example of a generic capsule. | ||
Future<T> Function(T) delayedEchoFactory<T>(CapsuleHandle _) { | ||
return (data) => Future.delayed(const Duration(seconds: 1), () => data); | ||
} | ||
|
||
/// {@template MyApp} | ||
/// The root of the infinite scroll demo. | ||
/// {@endtemplate} | ||
class MyApp extends StatelessWidget { | ||
/// {@macro MyApp} | ||
const MyApp({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return RearchBootstrapper( | ||
child: MaterialApp( | ||
title: 'Infinite Scroll Demo', | ||
home: Scaffold( | ||
appBar: AppBar(title: const Text('Infinite Scroll Demo')), | ||
body: const Column( | ||
children: [ | ||
Padding( | ||
padding: EdgeInsets.all(16), | ||
child: Text( | ||
'Selected items will not be disposed when they are ' | ||
'scrolled off screen (they are using keep alives)', | ||
), | ||
), | ||
Expanded(child: InfiniteList()), | ||
], | ||
), | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
/// {@template InfiniteList} | ||
/// The infinite list of numbers in the application. | ||
/// {@endtemplate} | ||
class InfiniteList extends StatelessWidget { | ||
/// {@macro InfiniteList} | ||
const InfiniteList({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return ListView.builder( | ||
itemBuilder: (context, index) => InfiniteScrollItem(index: index), | ||
); | ||
} | ||
} | ||
|
||
/// {@template InfiniteScrollItem} | ||
/// An item in the infinitely scrolling [ListView]. | ||
/// {@endtemplate} | ||
class InfiniteScrollItem extends RearchConsumer { | ||
/// {@macro InfiniteScrollItem} | ||
const InfiniteScrollItem({required this.index, super.key}); | ||
|
||
/// The index of this item. | ||
final int index; | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetHandle use) { | ||
final (keepAlive, setKeepAlive) = use.state(false); | ||
use.automaticKeepAlive(keepAlive: keepAlive); | ||
|
||
final factory = use(delayedEchoFactory<int>); | ||
final echoFuture = use.memo(() => factory(index), [factory, index]); | ||
final echoState = use.future(echoFuture); | ||
|
||
return ListTile( | ||
selected: keepAlive, | ||
onTap: () => setKeepAlive(!keepAlive), | ||
leading: Icon( | ||
keepAlive | ||
? Icons.task_alt_rounded | ||
: Icons.radio_button_unchecked_rounded, | ||
), | ||
title: switch (echoState) { | ||
AsyncData(:final data) => Text('$data'), | ||
AsyncLoading() => const Align( | ||
alignment: Alignment.centerLeft, | ||
child: CircularProgressIndicator.adaptive(), | ||
), | ||
AsyncError(:final error) => Text('$error'), | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
name: infinite_scroll | ||
description: Rearch example application showcasing infinite scroll. | ||
publish_to: 'none' | ||
|
||
environment: | ||
sdk: '>=3.0.0 <4.0.0' | ||
|
||
dependencies: | ||
flutter: | ||
sdk: flutter | ||
flutter_rearch: ^0.0.0-dev.7 | ||
rearch: ^0.0.0-dev.7 | ||
|
||
dev_dependencies: | ||
flutter_test: | ||
sdk: flutter | ||
|
||
flutter: | ||
uses-material-design: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_rearch/flutter_rearch.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
import 'package:infinite_scroll/main.dart'; | ||
|
||
const itemHeight = 48.0; | ||
const numItemsToShow = 5; | ||
const scrollOffset = Offset(0, 3 * numItemsToShow * itemHeight); | ||
|
||
void main() { | ||
testWidgets('keep alive items are kept alive when scrolled', (tester) async { | ||
Future<void> scrollUp() async { | ||
await tester.drag(find.byType(InfiniteList), scrollOffset); | ||
await tester.pump(); | ||
} | ||
|
||
Future<void> scrollDown() async { | ||
await tester.drag(find.byType(InfiniteList), -scrollOffset); | ||
await tester.pump(); | ||
} | ||
|
||
void expectItems(Iterable<int> iterable, Matcher matcher) { | ||
for (final i in iterable) { | ||
expect(find.text('$i'), matcher); | ||
} | ||
} | ||
|
||
await tester.pumpWidget( | ||
const RearchBootstrapper( | ||
child: MaterialApp( | ||
home: Scaffold( | ||
body: SizedBox( | ||
height: numItemsToShow * itemHeight, | ||
child: InfiniteList(), | ||
), | ||
), | ||
), | ||
), | ||
); | ||
|
||
expectItems(Iterable<int>.generate(numItemsToShow * 2), findsNothing); | ||
|
||
await tester.pumpAndSettle(); | ||
expectItems(Iterable<int>.generate(numItemsToShow), findsOneWidget); | ||
expectItems( | ||
Iterable<int>.generate(numItemsToShow, (i) => i + numItemsToShow), | ||
findsNothing, | ||
); | ||
|
||
await tester.tap(find.text('0')); | ||
await tester.tap(find.text('2')); | ||
await tester.pumpAndSettle(); | ||
|
||
await scrollDown(); | ||
await tester.pumpAndSettle(); | ||
expectItems(Iterable<int>.generate(numItemsToShow), findsNothing); | ||
|
||
await scrollUp(); | ||
expectItems([0, 2], findsOneWidget); | ||
expectItems([1, 3, 4, 5], findsNothing); | ||
|
||
await tester.pumpAndSettle(); | ||
expectItems(Iterable<int>.generate(numItemsToShow), findsOneWidget); | ||
expectItems( | ||
Iterable<int>.generate(numItemsToShow, (i) => i + numItemsToShow), | ||
findsNothing, | ||
); | ||
|
||
await tester.tap(find.text('0')); | ||
await tester.tap(find.text('2')); | ||
await tester.pump(); | ||
|
||
await scrollDown(); | ||
await tester.pumpAndSettle(); | ||
expectItems(Iterable<int>.generate(numItemsToShow), findsNothing); | ||
|
||
await scrollUp(); | ||
expectItems(Iterable<int>.generate(numItemsToShow * 2), findsNothing); | ||
|
||
await tester.pumpAndSettle(); | ||
expectItems(Iterable<int>.generate(numItemsToShow), findsOneWidget); | ||
expectItems( | ||
Iterable<int>.generate(numItemsToShow, (i) => i + numItemsToShow), | ||
findsNothing, | ||
); | ||
}); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<!-- | ||
If you are serving your web app in a path other than the root, change the | ||
href value below to reflect the base path you are serving from. | ||
The path provided below has to start and end with a slash "/" in order for | ||
it to work correctly. | ||
For more details: | ||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base | ||
This is a placeholder for base href that will be replaced by the value of | ||
the `--base-href` argument provided to `flutter build`. | ||
--> | ||
<base href="$FLUTTER_BASE_HREF"> | ||
|
||
<meta charset="UTF-8"> | ||
<meta content="IE=Edge" http-equiv="X-UA-Compatible"> | ||
<meta name="description" content="A new Flutter project."> | ||
|
||
<!-- iOS meta tags & icons --> | ||
<meta name="apple-mobile-web-app-capable" content="yes"> | ||
<meta name="apple-mobile-web-app-status-bar-style" content="black"> | ||
<meta name="apple-mobile-web-app-title" content="infinite_scroll"> | ||
<link rel="apple-touch-icon" href="icons/Icon-192.png"> | ||
|
||
<!-- Favicon --> | ||
<link rel="icon" type="image/png" href="favicon.png"/> | ||
|
||
<title>infinite_scroll</title> | ||
<link rel="manifest" href="manifest.json"> | ||
|
||
<script> | ||
// The value below is injected by flutter build, do not touch. | ||
var serviceWorkerVersion = null; | ||
</script> | ||
<!-- This script adds the flutter initialization JS code --> | ||
<script src="flutter.js" defer></script> | ||
</head> | ||
<body> | ||
<script> | ||
window.addEventListener('load', function(ev) { | ||
// Download main.dart.js | ||
_flutter.loader.loadEntrypoint({ | ||
serviceWorker: { | ||
serviceWorkerVersion: serviceWorkerVersion, | ||
}, | ||
onEntrypointLoaded: function(engineInitializer) { | ||
engineInitializer.initializeEngine().then(function(appRunner) { | ||
appRunner.runApp(); | ||
}); | ||
} | ||
}); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "infinite_scroll", | ||
"short_name": "infinite_scroll", | ||
"start_url": ".", | ||
"display": "standalone", | ||
"background_color": "#0175C2", | ||
"theme_color": "#0175C2", | ||
"description": "A new Flutter project.", | ||
"orientation": "portrait-primary", | ||
"prefer_related_applications": false, | ||
"icons": [ | ||
{ | ||
"src": "icons/Icon-192.png", | ||
"sizes": "192x192", | ||
"type": "image/png" | ||
}, | ||
{ | ||
"src": "icons/Icon-512.png", | ||
"sizes": "512x512", | ||
"type": "image/png" | ||
}, | ||
{ | ||
"src": "icons/Icon-maskable-192.png", | ||
"sizes": "192x192", | ||
"type": "image/png", | ||
"purpose": "maskable" | ||
}, | ||
{ | ||
"src": "icons/Icon-maskable-512.png", | ||
"sizes": "512x512", | ||
"type": "image/png", | ||
"purpose": "maskable" | ||
} | ||
] | ||
} |