album: scale gesture to change column count
This commit is contained in:
parent
4b9625afea
commit
aa697f3a37
6 changed files with 274 additions and 51 deletions
|
@ -64,7 +64,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
final permissions = await PermissionHandler().requestPermissions([
|
final permissions = await PermissionHandler().requestPermissions([
|
||||||
PermissionGroup.storage,
|
PermissionGroup.storage,
|
||||||
// unredacted EXIF with scoped storage (Android 10+)
|
// unredacted EXIF with scoped storage (Android 10+)
|
||||||
PermissionGroup.access_media_location,
|
PermissionGroup.accessMediaLocation,
|
||||||
]); // 350ms
|
]); // 350ms
|
||||||
if (permissions[PermissionGroup.storage] != PermissionStatus.granted) {
|
if (permissions[PermissionGroup.storage] != PermissionStatus.granted) {
|
||||||
unawaited(SystemNavigator.pop());
|
unawaited(SystemNavigator.pop());
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/widgets/album/sections.dart';
|
import 'package:aves/widgets/album/sections.dart';
|
||||||
|
import 'package:aves/widgets/album/sliver_transition_grid_delegate.dart';
|
||||||
import 'package:aves/widgets/album/thumbnail.dart';
|
import 'package:aves/widgets/album/thumbnail.dart';
|
||||||
import 'package:aves/widgets/album/transparent_material_page_route.dart';
|
import 'package:aves/widgets/album/transparent_material_page_route.dart';
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
|
@ -12,13 +13,13 @@ import 'package:provider/provider.dart';
|
||||||
class SectionSliver extends StatelessWidget {
|
class SectionSliver extends StatelessWidget {
|
||||||
final ImageCollection collection;
|
final ImageCollection collection;
|
||||||
final dynamic sectionKey;
|
final dynamic sectionKey;
|
||||||
|
final double columnCount;
|
||||||
static const columnCount = 4;
|
|
||||||
|
|
||||||
const SectionSliver({
|
const SectionSliver({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.collection,
|
@required this.collection,
|
||||||
@required this.sectionKey,
|
@required this.sectionKey,
|
||||||
|
@required this.columnCount,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -50,8 +51,7 @@ class SectionSliver extends StatelessWidget {
|
||||||
addAutomaticKeepAlives: false,
|
addAutomaticKeepAlives: false,
|
||||||
addRepaintBoundaries: true,
|
addRepaintBoundaries: true,
|
||||||
),
|
),
|
||||||
// TODO TLAD custom SliverGridDelegate / SliverGridLayout to lerp between columnCount
|
gridDelegate: SliverTransitionGridDelegateWithCrossAxisCount(
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: columnCount,
|
crossAxisCount: columnCount,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
176
lib/widgets/album/sliver_transition_grid_delegate.dart
Normal file
176
lib/widgets/album/sliver_transition_grid_delegate.dart
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
import 'dart:math' as math;
|
||||||
|
import 'dart:ui' show lerpDouble;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
|
class SliverTransitionGridDelegateWithCrossAxisCount extends SliverGridDelegate {
|
||||||
|
const SliverTransitionGridDelegateWithCrossAxisCount({
|
||||||
|
@required this.crossAxisCount,
|
||||||
|
this.mainAxisSpacing = 0.0,
|
||||||
|
this.crossAxisSpacing = 0.0,
|
||||||
|
this.childAspectRatio = 1.0,
|
||||||
|
}) : assert(crossAxisCount != null && crossAxisCount > 0),
|
||||||
|
assert(mainAxisSpacing != null && mainAxisSpacing >= 0),
|
||||||
|
assert(crossAxisSpacing != null && crossAxisSpacing >= 0),
|
||||||
|
assert(childAspectRatio != null && childAspectRatio > 0);
|
||||||
|
|
||||||
|
/// The number of children in the cross axis.
|
||||||
|
final double crossAxisCount;
|
||||||
|
|
||||||
|
/// The number of logical pixels between each child along the main axis.
|
||||||
|
final double mainAxisSpacing;
|
||||||
|
|
||||||
|
/// The number of logical pixels between each child along the cross axis.
|
||||||
|
final double crossAxisSpacing;
|
||||||
|
|
||||||
|
/// The ratio of the cross-axis to the main-axis extent of each child.
|
||||||
|
final double childAspectRatio;
|
||||||
|
|
||||||
|
@override
|
||||||
|
SliverGridLayout getLayout(SliverConstraints constraints) {
|
||||||
|
final t = crossAxisCount - crossAxisCount.truncateToDouble();
|
||||||
|
return SliverTransitionGridTileLayout(
|
||||||
|
current: _buildSettings(constraints, crossAxisCount),
|
||||||
|
floor: t != 0 ? _buildSettings(constraints, crossAxisCount.floorToDouble()) : null,
|
||||||
|
ceil: t != 0 ? _buildSettings(constraints, crossAxisCount.ceilToDouble()) : null,
|
||||||
|
t: t,
|
||||||
|
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SliverTransitionGridTileLayoutSettings _buildSettings(SliverConstraints constraints, double crossAxisCount) {
|
||||||
|
final double usableCrossAxisExtent = constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
|
||||||
|
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
|
||||||
|
final double childMainAxisExtent = childCrossAxisExtent / childAspectRatio;
|
||||||
|
final current = SliverTransitionGridTileLayoutSettings(
|
||||||
|
crossAxisCount: crossAxisCount,
|
||||||
|
mainAxisStride: childMainAxisExtent + mainAxisSpacing,
|
||||||
|
crossAxisStride: childCrossAxisExtent + crossAxisSpacing,
|
||||||
|
childMainAxisExtent: childMainAxisExtent,
|
||||||
|
childCrossAxisExtent: childCrossAxisExtent,
|
||||||
|
);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRelayout(SliverTransitionGridDelegateWithCrossAxisCount oldDelegate) {
|
||||||
|
return oldDelegate.crossAxisCount != crossAxisCount || oldDelegate.mainAxisSpacing != mainAxisSpacing || oldDelegate.crossAxisSpacing != crossAxisSpacing || oldDelegate.childAspectRatio != childAspectRatio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SliverTransitionGridTileLayoutSettings {
|
||||||
|
final double crossAxisCount;
|
||||||
|
|
||||||
|
/// The number of pixels from the leading edge of one tile to the leading edge
|
||||||
|
/// of the next tile in the main axis.
|
||||||
|
final double mainAxisStride;
|
||||||
|
|
||||||
|
/// The number of pixels from the leading edge of one tile to the leading edge
|
||||||
|
/// of the next tile in the cross axis.
|
||||||
|
final double crossAxisStride;
|
||||||
|
|
||||||
|
/// The number of pixels from the leading edge of one tile to the trailing
|
||||||
|
/// edge of the same tile in the main axis.
|
||||||
|
final double childMainAxisExtent;
|
||||||
|
|
||||||
|
/// The number of pixels from the leading edge of one tile to the trailing
|
||||||
|
/// edge of the same tile in the cross axis.
|
||||||
|
final double childCrossAxisExtent;
|
||||||
|
|
||||||
|
const SliverTransitionGridTileLayoutSettings({
|
||||||
|
@required this.crossAxisCount,
|
||||||
|
@required this.mainAxisStride,
|
||||||
|
@required this.crossAxisStride,
|
||||||
|
@required this.childMainAxisExtent,
|
||||||
|
@required this.childCrossAxisExtent,
|
||||||
|
}) : assert(crossAxisCount != null && crossAxisCount > 0),
|
||||||
|
assert(mainAxisStride != null && mainAxisStride >= 0),
|
||||||
|
assert(crossAxisStride != null && crossAxisStride >= 0),
|
||||||
|
assert(childMainAxisExtent != null && childMainAxisExtent >= 0),
|
||||||
|
assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SliverTransitionGridTileLayout extends SliverGridLayout {
|
||||||
|
/// Creates a layout that uses equally sized and spaced tiles.
|
||||||
|
///
|
||||||
|
/// All of the arguments must not be null and must not be negative. The
|
||||||
|
/// `crossAxisCount` argument must be greater than zero.
|
||||||
|
const SliverTransitionGridTileLayout({
|
||||||
|
@required this.current,
|
||||||
|
this.floor,
|
||||||
|
this.ceil,
|
||||||
|
this.t = 0,
|
||||||
|
@required this.reverseCrossAxis,
|
||||||
|
}) : assert(reverseCrossAxis != null);
|
||||||
|
|
||||||
|
final SliverTransitionGridTileLayoutSettings current, floor, ceil;
|
||||||
|
final double t;
|
||||||
|
|
||||||
|
/// Whether the children should be placed in the opposite order of increasing
|
||||||
|
/// coordinates in the cross axis.
|
||||||
|
///
|
||||||
|
/// For example, if the cross axis is horizontal, the children are placed from
|
||||||
|
/// left to right when [reverseCrossAxis] is false and from right to left when
|
||||||
|
/// [reverseCrossAxis] is true.
|
||||||
|
///
|
||||||
|
/// Typically set to the return value of [axisDirectionIsReversed] applied to
|
||||||
|
/// the [SliverConstraints.crossAxisDirection].
|
||||||
|
final bool reverseCrossAxis;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int getMinChildIndexForScrollOffset(double scrollOffset) {
|
||||||
|
final settings = t == 0 ? current : floor;
|
||||||
|
final index = settings.mainAxisStride > 0.0 ? (settings.crossAxisCount * (scrollOffset ~/ settings.mainAxisStride)).floor() : 0;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int getMaxChildIndexForScrollOffset(double scrollOffset) {
|
||||||
|
final settings = t == 0 ? current : floor;
|
||||||
|
if (settings.mainAxisStride > 0.0) {
|
||||||
|
final int mainAxisCount = (scrollOffset / settings.mainAxisStride).ceil();
|
||||||
|
final index = math.max(0, settings.crossAxisCount * mainAxisCount - 1).ceil();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _getScrollOffset(int index, SliverTransitionGridTileLayoutSettings settings) {
|
||||||
|
return (index ~/ settings.crossAxisCount) * settings.mainAxisStride;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _getCrossAxisOffset(int index, SliverTransitionGridTileLayoutSettings settings) {
|
||||||
|
final double crossAxisStart = (index % settings.crossAxisCount) * settings.crossAxisStride;
|
||||||
|
if (reverseCrossAxis) {
|
||||||
|
return settings.crossAxisCount * settings.crossAxisStride - crossAxisStart - settings.childCrossAxisExtent - (settings.crossAxisStride - settings.childCrossAxisExtent);
|
||||||
|
}
|
||||||
|
return crossAxisStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
SliverGridGeometry getGeometryForChildIndex(int index) {
|
||||||
|
return SliverGridGeometry(
|
||||||
|
scrollOffset: t == 0 ? _getScrollOffset(index, current) : lerpDouble(_getScrollOffset(index, floor), _getScrollOffset(index, ceil), t),
|
||||||
|
crossAxisOffset: t == 0 ? _getCrossAxisOffset(index, current) : lerpDouble(_getCrossAxisOffset(index, floor), _getCrossAxisOffset(index, ceil), t),
|
||||||
|
mainAxisExtent: current.childMainAxisExtent,
|
||||||
|
crossAxisExtent: current.childCrossAxisExtent,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double computeMaxScrollOffset(int childCount) {
|
||||||
|
assert(childCount != null);
|
||||||
|
|
||||||
|
if (t != 0) {
|
||||||
|
final index = childCount - 1;
|
||||||
|
var maxScrollOffset = lerpDouble(_getScrollOffset(index, floor), _getScrollOffset(index, ceil), t) + current.mainAxisStride;
|
||||||
|
return maxScrollOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int mainAxisCount = ((childCount - 1) ~/ current.crossAxisCount) + 1;
|
||||||
|
final double mainAxisSpacing = current.mainAxisStride - current.childMainAxisExtent;
|
||||||
|
final maxScrollOffset = current.mainAxisStride * mainAxisCount - mainAxisSpacing;
|
||||||
|
return maxScrollOffset;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,8 +19,9 @@ class Thumbnail extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final image = ImagePreview(
|
final image = ImagePreview(
|
||||||
entry: entry,
|
entry: entry,
|
||||||
width: extent,
|
// TODO TLAD smarter sizing, but shouldn't only depend on `extent` so that it doesn't reload during gridview scaling
|
||||||
height: extent,
|
width: 50,
|
||||||
|
height: 50,
|
||||||
builder: (bytes) {
|
builder: (bytes) {
|
||||||
return Hero(
|
return Hero(
|
||||||
tag: entry.uri,
|
tag: entry.uri,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/model/image_collection.dart';
|
import 'package:aves/model/image_collection.dart';
|
||||||
import 'package:aves/widgets/album/collection_section.dart';
|
import 'package:aves/widgets/album/collection_section.dart';
|
||||||
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
||||||
|
@ -7,6 +9,7 @@ import 'package:provider/provider.dart';
|
||||||
class ThumbnailCollection extends StatelessWidget {
|
class ThumbnailCollection extends StatelessWidget {
|
||||||
final Widget appBar;
|
final Widget appBar;
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
final ValueNotifier<double> _columnCountNotifier = ValueNotifier(4);
|
||||||
|
|
||||||
ThumbnailCollection({
|
ThumbnailCollection({
|
||||||
Key key,
|
Key key,
|
||||||
|
@ -29,13 +32,32 @@ class ThumbnailCollection extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final scrollView = CustomScrollView(
|
return SafeArea(
|
||||||
|
child: Selector<MediaQueryData, double>(
|
||||||
|
selector: (c, mq) => mq.viewInsets.bottom,
|
||||||
|
builder: (c, mqViewInsetsBottom, child) {
|
||||||
|
return ValueListenableBuilder(
|
||||||
|
valueListenable: _columnCountNotifier,
|
||||||
|
builder: (context, columnCount, child) => GridScaleGestureDetector(
|
||||||
|
columnCountNotifier: _columnCountNotifier,
|
||||||
|
child: DraggableScrollbar(
|
||||||
|
heightScrollThumb: 48,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
scrollThumbBuilder: _thumbArrowBuilder(false),
|
||||||
|
controller: _scrollController,
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
// padding to get scroll thumb below app bar, above nav bar
|
||||||
|
top: topPadding,
|
||||||
|
bottom: mqViewInsetsBottom,
|
||||||
|
),
|
||||||
|
child: CustomScrollView(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
if (appBar != null) appBar,
|
if (appBar != null) appBar,
|
||||||
...sectionKeys.map((sectionKey) => SectionSliver(
|
...sectionKeys.map((sectionKey) => SectionSliver(
|
||||||
collection: collection,
|
collection: collection,
|
||||||
sectionKey: sectionKey,
|
sectionKey: sectionKey,
|
||||||
|
columnCount: columnCount,
|
||||||
)),
|
)),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Selector<MediaQueryData, double>(
|
child: Selector<MediaQueryData, double>(
|
||||||
|
@ -46,23 +68,9 @@ class ThumbnailCollection extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
|
||||||
|
|
||||||
return SafeArea(
|
|
||||||
child: Selector<MediaQueryData, double>(
|
|
||||||
selector: (c, mq) => mq.viewInsets.bottom,
|
|
||||||
builder: (c, mqViewInsetsBottom, child) {
|
|
||||||
return DraggableScrollbar(
|
|
||||||
heightScrollThumb: 48,
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
scrollThumbBuilder: _thumbArrowBuilder(false),
|
|
||||||
controller: _scrollController,
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
// padding to get scroll thumb below app bar, above nav bar
|
|
||||||
top: topPadding,
|
|
||||||
bottom: mqViewInsetsBottom,
|
|
||||||
),
|
),
|
||||||
child: scrollView,
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -112,3 +120,41 @@ class ThumbnailCollection extends StatelessWidget {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GridScaleGestureDetector extends StatefulWidget {
|
||||||
|
final ValueNotifier<double> columnCountNotifier;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const GridScaleGestureDetector({
|
||||||
|
@required this.columnCountNotifier,
|
||||||
|
@required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GridScaleGestureDetectorState createState() => _GridScaleGestureDetectorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
|
||||||
|
double _start;
|
||||||
|
|
||||||
|
ValueNotifier<double> get countNotifier => widget.columnCountNotifier;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onScaleStart: (details) => _start = countNotifier.value,
|
||||||
|
onScaleUpdate: (details) {
|
||||||
|
final s = details.scale;
|
||||||
|
_updateColumnCount(s <= 1 ? lerpDouble(_start * 2, _start, s) : lerpDouble(_start, _start / 2, s / 6));
|
||||||
|
},
|
||||||
|
onScaleEnd: (details) {
|
||||||
|
_updateColumnCount(countNotifier.value.roundToDouble());
|
||||||
|
},
|
||||||
|
child: widget.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateColumnCount(double count) {
|
||||||
|
countNotifier.value = count.clamp(2.0, 8.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
30
pubspec.lock
30
pubspec.lock
|
@ -105,7 +105,7 @@ packages:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.6"
|
||||||
flutter_staggered_grid_view:
|
flutter_staggered_grid_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -118,17 +118,17 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: d30ab5fbe87f590fdf16201e8195e8449344804f
|
resolved-ref: "14be154f50f5d14e88cc05b93b12377012b8905a"
|
||||||
url: "git://github.com/deckerst/flutter_sticky_header.git"
|
url: "git://github.com/deckerst/flutter_sticky_header.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.4.0"
|
version: "0.4.2"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.17.1"
|
version: "0.17.2"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -152,7 +152,7 @@ packages:
|
||||||
name: google_maps_flutter
|
name: google_maps_flutter
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.23+1"
|
version: "0.5.24+1"
|
||||||
image:
|
image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -236,7 +236,7 @@ packages:
|
||||||
name: pdf
|
name: pdf
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.5.0"
|
||||||
pedantic:
|
pedantic:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -250,7 +250,7 @@ packages:
|
||||||
name: permission_handler
|
name: permission_handler
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.0+hotfix.3"
|
version: "4.3.0"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -306,28 +306,28 @@ packages:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.6+1"
|
version: "0.5.6+2"
|
||||||
shared_preferences_macos:
|
shared_preferences_macos:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_macos
|
name: shared_preferences_macos
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.1+5"
|
version: "0.0.1+6"
|
||||||
shared_preferences_platform_interface:
|
shared_preferences_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.3"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2+3"
|
version: "0.1.2+4"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -346,7 +346,7 @@ packages:
|
||||||
name: sqflite
|
name: sqflite
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -430,21 +430,21 @@ packages:
|
||||||
name: video_player
|
name: video_player
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.7"
|
version: "0.10.8+1"
|
||||||
video_player_platform_interface:
|
video_player_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: video_player_platform_interface
|
name: video_player_platform_interface
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.5"
|
||||||
video_player_web:
|
video_player_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: video_player_web
|
name: video_player_web
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2"
|
version: "0.1.2+1"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
Loading…
Reference in a new issue