Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Review feedback and some tests
  • Loading branch information
Piinks committed Aug 17, 2023
commit 1e2129c4b0a79df34b9a238c259d4940c2fc8bad
30 changes: 30 additions & 0 deletions packages/two_dimensional_scrollables/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
10 changes: 10 additions & 0 deletions packages/two_dimensional_scrollables/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: "0ed17dd5a24676c897b5268da976717c22e68780"
channel: "[user-branch]"

project_type: package
10 changes: 6 additions & 4 deletions packages/two_dimensional_scrollables/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Two Dimensional Scrollables

A package that provides widgets that scroll in two dimensions, built on the
two-dimensional foundation of the Flutter framework.

## Features

This package provides support for a TableView widget that scrolls in both the
vertical and horizontal axes.

In the future, additional widgets from this package will include:
* TreeView
* TreeTableView

### TableView

`TableView` is a subclass of `TwoDimensionalScrollView`, building its provided
Expand All @@ -28,13 +26,15 @@ Run this command with Flutter:
```sh
$ flutter pub add two_dimensional_scrollables
```

### Import it

Now in your Dart code, you can use:

```sh
import 'package:two_dimensional_scrollables/table_view.dart';
```

## Usage

### TableView
Expand Down Expand Up @@ -81,11 +81,13 @@ TableView.builder(
```

## Changelog

See the
[Changelog](https://github.com/flutter/packages/blob/main/packages/two_dimensional_scrollables/CHANGELOG.md)
for a list of new features and breaking changes.

## Roadmap

See the [GitHub project](https://github.com/orgs/flutter/projects/32/) for a
prioritized list of feature requests and known issues.

Expand Down
44 changes: 20 additions & 24 deletions packages/two_dimensional_scrollables/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@ import 'package:flutter/material.dart';
import 'package:two_dimensional_scrollables/table_view.dart';

// ignore_for_file: avoid_print
// ignore_for_file: only_throw_errors

void main() {
runApp(const TableExampleApp());
}

/// A sample application that utilizes the TableView API
class TableExampleApp extends StatelessWidget {
/// Crates an instance of teh TableView example app.
const TableExampleApp({super.key, this.controller});

/// A scroll controller to pass to the TableView for testing purposes.
final ScrollController? controller;
/// Creates an instance of the TableView example app.
const TableExampleApp({super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -28,32 +24,28 @@ class TableExampleApp extends StatelessWidget {
theme: ThemeData(
useMaterial3: true,
),
home: TableExample(controller: controller),
home: const TableExample(),
);
}
}

/// The class containing the TableView for the sample application.
class TableExample extends StatefulWidget {
/// Creates a screen that demonstrates the TableView widget.
const TableExample({super.key, this.controller});

/// A scroll controller to pass to the TableView for testing purposes.
final ScrollController? controller;
const TableExample({super.key});

@override
State<TableExample> createState() => _TableExampleState();
}

class _TableExampleState extends State<TableExample> {
late final ScrollController _controller;
late int _rowCount;
late final ScrollController _verticalController;
int _rowCount = 20;

@override
void initState() {
_controller = widget.controller ?? ScrollController();
_rowCount = 20;
super.initState();
_verticalController = ScrollController();
}

@override
Expand All @@ -65,7 +57,8 @@ class _TableExampleState extends State<TableExample> {
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: TableView.builder(
verticalDetails: ScrollableDetails.vertical(controller: _controller),
verticalDetails:
ScrollableDetails.vertical(controller: _verticalController),
cellBuilder: _buildCell,
columnCount: 20,
columnBuilder: _buildColumnSpan,
Expand All @@ -76,13 +69,14 @@ class _TableExampleState extends State<TableExample> {
persistentFooterButtons: <Widget>[
TextButton(
onPressed: () {
_controller.jumpTo(0);
_verticalController.jumpTo(0);
},
child: const Text('Jump to Top'),
),
TextButton(
onPressed: () {
_controller.jumpTo(_controller.position.maxScrollExtent);
_verticalController
.jumpTo(_verticalController.position.maxScrollExtent);
},
child: const Text('Jump to Bottom'),
),
Expand All @@ -100,9 +94,10 @@ class _TableExampleState extends State<TableExample> {

TableViewCell _buildCell(BuildContext context, TableVicinity vicinity) {
return TableViewCell(
child: Center(
child: Text('Tile c: ${vicinity.column}, r: ${vicinity.row}'),
));
child: Center(
child: Text('Tile c: ${vicinity.column}, r: ${vicinity.row}'),
),
);
}

TableSpan _buildColumnSpan(int index) {
Expand Down Expand Up @@ -153,7 +148,8 @@ class _TableExampleState extends State<TableExample> {
onEnter: (_) => print('Entered column $index'),
);
}
throw 'unreachable';
throw AssertionError(
'This should be unreachable, as every index is accounted for in the switch clauses.');
}

TableSpan _buildRowSpan(int index) {
Expand All @@ -166,7 +162,6 @@ class _TableExampleState extends State<TableExample> {
),
);

// return const FixedRawTableDimensionSpec(35);
switch (index % 3) {
case 0:
return TableSpan(
Expand All @@ -193,6 +188,7 @@ class _TableExampleState extends State<TableExample> {
extent: const FractionalTableSpanExtent(0.15),
);
}
throw 'unreachable';
throw AssertionError(
'This should be unreachable, as every index is accounted for in the switch clauses.');
}
}
72 changes: 2 additions & 70 deletions packages/two_dimensional_scrollables/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,92 +1,24 @@
name: table_view_example
description: 'A sample application that uses TableView'
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
publish_to: 'none'

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1

environment:
sdk: '>=3.1.0-331.0.dev <4.0.0'

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
two_dimensional_scrollables:
path: ../


# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2

dev_dependencies:
flutter_lints: ^2.0.0
flutter_test:
sdk: flutter

# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:

# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true

# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg

# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware

# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages

# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2014 The Flutter Authors. 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:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:table_view_example/main.dart';

void main() {
testWidgets('Example app builds & scrolls', (WidgetTester tester) async {
await tester.pumpWidget(const TableExampleApp());
await tester.pump();

expect(find.text('Jump to Top'), findsOneWidget);
expect(find.text('Jump to Bottom'), findsOneWidget);
expect(find.text('Add 10 Rows'), findsOneWidget);

final Finder scrollable = find.byWidgetPredicate((Widget widget) {
if (widget is Scrollable) {
return widget.axisDirection == AxisDirection.down;
}
return false;
});
final ScrollPosition position =
(tester.state(scrollable) as ScrollableState).position;
expect(position.axis, Axis.vertical);
expect(position.pixels, 0.0);
position.jumpTo(10);
await tester.pump();
expect(position.pixels, 10.0);
});

testWidgets('Example app buttons work', (WidgetTester tester) async {
await tester.pumpWidget(const TableExampleApp());
await tester.pump();

final Finder scrollable = find.byWidgetPredicate((Widget widget) {
if (widget is Scrollable) {
return widget.axisDirection == AxisDirection.down;
}
return false;
});
final ScrollPosition position =
(tester.state(scrollable) as ScrollableState).position;

expect(position.maxScrollExtent, greaterThan(750));
await tester.tap(find.text('Add 10 Rows'));
await tester.pump();
expect(position.maxScrollExtent, greaterThan(1380));
await tester.tap(find.text('Jump to Bottom'));
await tester.pump();
expect(position.pixels, greaterThan(1380));
await tester.tap(find.text('Jump to Top'));
await tester.pump();
expect(position.pixels, 0.0);
});
}
Loading