Polish editorial screen
This commit is contained in:
parent
fd0a044a8f
commit
bd3a87edd9
@ -39,7 +39,7 @@ class ArchPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ArchPoint> _getArchPts(Size size, ArchType type) {
|
List<ArchPoint> _getArchPts(Size size, ArchType type) {
|
||||||
double distanceFromTop = 100;
|
double distanceFromTop = size.width / 3;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ArchType.pyramid:
|
case ArchType.pyramid:
|
||||||
return [
|
return [
|
||||||
@ -60,19 +60,19 @@ List<ArchPoint> _getArchPts(Size size, ArchType type) {
|
|||||||
case ArchType.arch:
|
case ArchType.arch:
|
||||||
return [
|
return [
|
||||||
ArchPoint(Offset(0, size.height)),
|
ArchPoint(Offset(0, size.height)),
|
||||||
ArchPoint(Offset(0, distanceFromTop * 2)),
|
ArchPoint(Offset(0, size.width / 2)),
|
||||||
ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)),
|
ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)),
|
||||||
ArchPoint(Offset(size.width, distanceFromTop * 2), Offset(size.width, 0)),
|
ArchPoint(Offset(size.width, size.width / 2), Offset(size.width, 0)),
|
||||||
ArchPoint(Offset(size.width, size.height)),
|
ArchPoint(Offset(size.width, size.height)),
|
||||||
];
|
];
|
||||||
case ArchType.wideArch:
|
case ArchType.wideArch:
|
||||||
return [
|
return [
|
||||||
ArchPoint(Offset(0, size.height)),
|
ArchPoint(Offset(0, size.height)),
|
||||||
ArchPoint(Offset(0, distanceFromTop * 2)),
|
ArchPoint(Offset(0, size.width / 2)),
|
||||||
ArchPoint(Offset(0, distanceFromTop)),
|
ArchPoint(Offset(0, distanceFromTop)),
|
||||||
ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)),
|
ArchPoint(Offset(size.width / 2, 0), Offset(0, 0)),
|
||||||
ArchPoint(Offset(size.width, distanceFromTop), Offset(size.width, 0)),
|
ArchPoint(Offset(size.width, distanceFromTop), Offset(size.width, 0)),
|
||||||
ArchPoint(Offset(size.width, distanceFromTop * 2)),
|
ArchPoint(Offset(size.width, size.width / 2)),
|
||||||
ArchPoint(Offset(size.width, size.height)),
|
ArchPoint(Offset(size.width, size.height)),
|
||||||
];
|
];
|
||||||
case ArchType.flatPyramid:
|
case ArchType.flatPyramid:
|
||||||
|
@ -160,7 +160,6 @@ class CollectibleFoundScreen extends StatelessWidget {
|
|||||||
return AppBtn.from(
|
return AppBtn.from(
|
||||||
text: $strings.collectibleFoundButtonViewCollection,
|
text: $strings.collectibleFoundButtonViewCollection,
|
||||||
isSecondary: true,
|
isSecondary: true,
|
||||||
expand: true,
|
|
||||||
onPressed: () => _handleViewCollectionPressed(context),
|
onPressed: () => _handleViewCollectionPressed(context),
|
||||||
)
|
)
|
||||||
.animate()
|
.animate()
|
||||||
|
@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart';
|
|||||||
import 'package:flutter_circular_text/circular_text.dart';
|
import 'package:flutter_circular_text/circular_text.dart';
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import 'package:wonders/common_libs.dart';
|
import 'package:wonders/common_libs.dart';
|
||||||
|
import 'package:wonders/logic/common/platform_info.dart';
|
||||||
import 'package:wonders/logic/common/string_utils.dart';
|
import 'package:wonders/logic/common/string_utils.dart';
|
||||||
import 'package:wonders/logic/data/wonder_data.dart';
|
import 'package:wonders/logic/data/wonder_data.dart';
|
||||||
import 'package:wonders/ui/common/app_icons.dart';
|
import 'package:wonders/ui/common/app_icons.dart';
|
||||||
@ -72,7 +73,9 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
|
|||||||
bool shortMode = constraints.biggest.height < 700;
|
bool shortMode = constraints.biggest.height < 700;
|
||||||
double illustrationHeight = shortMode ? 250 : 280;
|
double illustrationHeight = shortMode ? 250 : 280;
|
||||||
double minAppBarHeight = shortMode ? 80 : 120;
|
double minAppBarHeight = shortMode ? 80 : 120;
|
||||||
double maxAppBarHeight = shortMode ? 400 : 500;
|
|
||||||
|
/// Attempt to maintain a similar aspect ratio for the image within the app-bar
|
||||||
|
double maxAppBarHeight = min(context.widthPx, $styles.sizes.maxContentWidth1) * 1.5;
|
||||||
|
|
||||||
return PopRouterOnOverScroll(
|
return PopRouterOnOverScroll(
|
||||||
controller: _scroller,
|
controller: _scroller,
|
||||||
@ -82,16 +85,7 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
|
|||||||
children: [
|
children: [
|
||||||
/// Background
|
/// Background
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: ValueListenableBuilder<double>(
|
child: ColoredBox(color: widget.data.type.bgColor),
|
||||||
valueListenable: _scrollPos,
|
|
||||||
builder: (_, value, __) {
|
|
||||||
bool showBg = value < 700;
|
|
||||||
return AnimatedContainer(
|
|
||||||
duration: $styles.times.fast,
|
|
||||||
color: widget.data.type.bgColor.withOpacity(showBg ? 1 : 0),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
/// Top Illustration - Sits underneath the scrolling content, fades out as it scrolls
|
/// Top Illustration - Sits underneath the scrolling content, fades out as it scrolls
|
||||||
@ -112,7 +106,7 @@ class _WonderEditorialScreenState extends State<WonderEditorialScreen> {
|
|||||||
/// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration
|
/// Scrolling content - Includes an invisible gap at the top, and then scrolls over the illustration
|
||||||
TopCenter(
|
TopCenter(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: $styles.sizes.maxContentWidth1,
|
//width: $styles.sizes.maxContentWidth1,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
primary: false,
|
primary: false,
|
||||||
controller: _scroller,
|
controller: _scroller,
|
||||||
|
@ -47,28 +47,33 @@ class _AppBar extends StatelessWidget {
|
|||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: [
|
children: [
|
||||||
AnimatedSwitcher(
|
AnimatedSwitcher(
|
||||||
duration: $styles.times.fast * .5,
|
duration: $styles.times.med,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
key: ValueKey(showOverlay),
|
key: ValueKey(showOverlay),
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: [
|
children: [
|
||||||
/// Masked image
|
/// Masked image
|
||||||
ClipPath(
|
Center(
|
||||||
// Switch arch type to Rect if we are showing the title bar
|
child: SizedBox(
|
||||||
clipper: showOverlay ? null : ArchClipper(arch),
|
width: showOverlay ? double.infinity : $styles.sizes.maxContentWidth1,
|
||||||
child: ValueListenableBuilder<double>(
|
child: ClipPath(
|
||||||
valueListenable: scrollPos,
|
// Switch arch type to Rect if we are showing the title bar
|
||||||
builder: (_, value, child) {
|
clipper: showOverlay ? null : ArchClipper(arch),
|
||||||
double opacity = (.4 + (value / 1500)).clamp(0, 1);
|
child: ValueListenableBuilder<double>(
|
||||||
return ScalingListItem(
|
valueListenable: scrollPos,
|
||||||
scrollPos: scrollPos,
|
builder: (_, value, child) {
|
||||||
child: Image.asset(
|
double opacity = (.4 + (value / 1500)).clamp(0, 1);
|
||||||
wonderType.photo1,
|
return ScalingListItem(
|
||||||
fit: BoxFit.cover,
|
scrollPos: scrollPos,
|
||||||
opacity: AlwaysStoppedAnimation(opacity),
|
child: Image.asset(
|
||||||
),
|
wonderType.photo1,
|
||||||
);
|
fit: BoxFit.cover,
|
||||||
},
|
opacity: AlwaysStoppedAnimation(opacity),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -89,50 +89,57 @@ class _ScrollingContent extends StatelessWidget {
|
|||||||
sliver: SliverPadding(
|
sliver: SliverPadding(
|
||||||
padding: EdgeInsets.symmetric(vertical: $styles.insets.md),
|
padding: EdgeInsets.symmetric(vertical: $styles.insets.md),
|
||||||
sliver: SliverList(
|
sliver: SliverList(
|
||||||
delegate: SliverChildListDelegate([
|
delegate: SliverChildListDelegate.fixed([
|
||||||
..._contentSection([
|
Center(
|
||||||
Center(child: buildHiddenCollectible(slot: 0)),
|
child: SizedBox(
|
||||||
|
width: $styles.sizes.maxContentWidth1,
|
||||||
|
child: Column(children: [
|
||||||
|
..._contentSection([
|
||||||
|
Center(child: buildHiddenCollectible(slot: 0)),
|
||||||
|
|
||||||
/// History 1
|
/// History 1
|
||||||
buildDropCapText(data.historyInfo1),
|
buildDropCapText(data.historyInfo1),
|
||||||
|
|
||||||
/// Quote1
|
/// Quote1
|
||||||
_CollapsingPullQuoteImage(data: data, scrollPos: scrollPos),
|
_CollapsingPullQuoteImage(data: data, scrollPos: scrollPos),
|
||||||
Center(child: buildHiddenCollectible(slot: 1)),
|
Center(child: buildHiddenCollectible(slot: 1)),
|
||||||
|
|
||||||
/// Callout1
|
/// Callout1
|
||||||
_Callout(text: data.callout1),
|
_Callout(text: data.callout1),
|
||||||
|
|
||||||
/// History 2
|
/// History 2
|
||||||
buildText(data.historyInfo2),
|
buildText(data.historyInfo2),
|
||||||
_SectionDivider(scrollPos, sectionNotifier, index: 1),
|
_SectionDivider(scrollPos, sectionNotifier, index: 1),
|
||||||
|
|
||||||
/// Construction 1
|
/// Construction 1
|
||||||
buildDropCapText(data.constructionInfo1),
|
buildDropCapText(data.constructionInfo1),
|
||||||
Center(child: buildHiddenCollectible(slot: 2)),
|
Center(child: buildHiddenCollectible(slot: 2)),
|
||||||
]),
|
]),
|
||||||
Gap($styles.insets.md),
|
Gap($styles.insets.md),
|
||||||
_YouTubeThumbnail(id: data.videoId, caption: data.videoCaption),
|
_YouTubeThumbnail(id: data.videoId, caption: data.videoCaption),
|
||||||
Gap($styles.insets.md),
|
Gap($styles.insets.md),
|
||||||
..._contentSection([
|
..._contentSection([
|
||||||
/// Callout2
|
/// Callout2
|
||||||
Gap($styles.insets.xs),
|
Gap($styles.insets.xs),
|
||||||
_Callout(text: data.callout2),
|
_Callout(text: data.callout2),
|
||||||
|
|
||||||
/// Construction 2
|
/// Construction 2
|
||||||
buildText(data.constructionInfo2),
|
buildText(data.constructionInfo2),
|
||||||
_SlidingImageStack(scrollPos: scrollPos, type: data.type),
|
_SlidingImageStack(scrollPos: scrollPos, type: data.type),
|
||||||
_SectionDivider(scrollPos, sectionNotifier, index: 2),
|
_SectionDivider(scrollPos, sectionNotifier, index: 2),
|
||||||
|
|
||||||
/// Location
|
/// Location
|
||||||
buildDropCapText(data.locationInfo1),
|
buildDropCapText(data.locationInfo1),
|
||||||
_LargeSimpleQuote(text: data.pullQuote2, author: data.pullQuote2Author),
|
_LargeSimpleQuote(text: data.pullQuote2, author: data.pullQuote2Author),
|
||||||
buildText(data.locationInfo2),
|
buildText(data.locationInfo2),
|
||||||
]),
|
]),
|
||||||
Gap($styles.insets.md),
|
Gap($styles.insets.md),
|
||||||
_MapsThumbnail(data, height: 200),
|
_MapsThumbnail(data, height: 200),
|
||||||
Gap($styles.insets.md),
|
Gap($styles.insets.md),
|
||||||
..._contentSection([Center(child: buildHiddenCollectible(slot: 3))]),
|
..._contentSection([Center(child: buildHiddenCollectible(slot: 3))]),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -221,6 +228,7 @@ class _MapsThumbnailState extends State<_MapsThumbnail> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
void handlePressed() => context.push(ScreenPaths.maps(widget.data.type));
|
void handlePressed() => context.push(ScreenPaths.maps(widget.data.type));
|
||||||
|
if (PlatformInfo.isDesktop) return Placeholder();
|
||||||
return MergeSemantics(
|
return MergeSemantics(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -11,83 +11,88 @@ class _TitleText extends StatelessWidget {
|
|||||||
child: DefaultTextColor(
|
child: DefaultTextColor(
|
||||||
color: $styles.colors.offWhite,
|
color: $styles.colors.offWhite,
|
||||||
child: StaticTextScale(
|
child: StaticTextScale(
|
||||||
child: Column(
|
child: Center(
|
||||||
children: [
|
child: SizedBox(
|
||||||
Gap($styles.insets.md),
|
width: $styles.sizes.maxContentWidth1,
|
||||||
Gap(30),
|
child: Column(
|
||||||
|
|
||||||
/// Sub-title row
|
|
||||||
SeparatedRow(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: $styles.insets.sm),
|
|
||||||
separatorBuilder: () => Gap($styles.insets.sm),
|
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Gap($styles.insets.md),
|
||||||
child: Divider(
|
Gap(30),
|
||||||
color: data.type.fgColor,
|
|
||||||
).animate().scale(curve: Curves.easeOut, delay: 500.ms),
|
/// Sub-title row
|
||||||
|
SeparatedRow(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: $styles.insets.sm),
|
||||||
|
separatorBuilder: () => Gap($styles.insets.sm),
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Divider(
|
||||||
|
color: data.type.fgColor,
|
||||||
|
).animate().scale(curve: Curves.easeOut, delay: 500.ms),
|
||||||
|
),
|
||||||
|
Semantics(
|
||||||
|
header: true,
|
||||||
|
sortKey: OrdinalSortKey(1),
|
||||||
|
child: Text(
|
||||||
|
data.subTitle.toUpperCase(),
|
||||||
|
style: $styles.text.title2,
|
||||||
|
).animate().fade(delay: 100.ms),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Divider(
|
||||||
|
color: data.type.fgColor,
|
||||||
|
).animate().scale(curve: Curves.easeOut, delay: 500.ms),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
Gap($styles.insets.md),
|
||||||
|
|
||||||
|
/// Wonder title text
|
||||||
Semantics(
|
Semantics(
|
||||||
header: true,
|
sortKey: OrdinalSortKey(0),
|
||||||
sortKey: OrdinalSortKey(1),
|
child: ListenableBuilder(
|
||||||
child: Text(
|
listenable: scroller,
|
||||||
data.subTitle.toUpperCase(),
|
builder: (_, __) {
|
||||||
style: $styles.text.title2,
|
final yPos = ContextUtils.getGlobalPos(context)?.dy ?? 0;
|
||||||
).animate().fade(delay: 100.ms),
|
bool enableHero = yPos > -100;
|
||||||
|
return WonderTitleText(data, enableHero: enableHero);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
Expanded(
|
Gap($styles.insets.xs),
|
||||||
child: Divider(
|
|
||||||
color: data.type.fgColor,
|
/// Region
|
||||||
).animate().scale(curve: Curves.easeOut, delay: 500.ms),
|
Text(
|
||||||
|
data.regionTitle.toUpperCase(),
|
||||||
|
style: $styles.text.title1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
Gap($styles.insets.md),
|
||||||
),
|
|
||||||
Gap($styles.insets.md),
|
|
||||||
|
|
||||||
/// Wonder title text
|
/// Compass divider
|
||||||
Semantics(
|
ExcludeSemantics(
|
||||||
sortKey: OrdinalSortKey(0),
|
child: Padding(
|
||||||
child: ListenableBuilder(
|
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
|
||||||
listenable: scroller,
|
child: ListenableBuilder(
|
||||||
builder: (_, __) {
|
listenable: scroller,
|
||||||
final yPos = ContextUtils.getGlobalPos(context)?.dy ?? 0;
|
builder: (_, __) => CompassDivider(
|
||||||
bool enableHero = yPos > -100;
|
isExpanded: scroller.position.pixels <= 0,
|
||||||
return WonderTitleText(data, enableHero: enableHero);
|
linesColor: data.type.fgColor,
|
||||||
}),
|
compassColor: $styles.colors.offWhite,
|
||||||
),
|
),
|
||||||
Gap($styles.insets.xs),
|
),
|
||||||
|
|
||||||
/// Region
|
|
||||||
Text(
|
|
||||||
data.regionTitle.toUpperCase(),
|
|
||||||
style: $styles.text.title1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Gap($styles.insets.md),
|
|
||||||
|
|
||||||
/// Compass divider
|
|
||||||
ExcludeSemantics(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
|
|
||||||
child: ListenableBuilder(
|
|
||||||
listenable: scroller,
|
|
||||||
builder: (_, __) => CompassDivider(
|
|
||||||
isExpanded: scroller.position.pixels <= 0,
|
|
||||||
linesColor: data.type.fgColor,
|
|
||||||
compassColor: $styles.colors.offWhite,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Gap($styles.insets.sm),
|
||||||
),
|
|
||||||
Gap($styles.insets.sm),
|
|
||||||
|
|
||||||
/// Date
|
/// Date
|
||||||
Text(
|
Text(
|
||||||
$strings.titleLabelDate(StringUtils.formatYr(data.startYr), StringUtils.formatYr(data.endYr)),
|
$strings.titleLabelDate(StringUtils.formatYr(data.startYr), StringUtils.formatYr(data.endYr)),
|
||||||
style: $styles.text.h4,
|
style: $styles.text.h4,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Gap($styles.insets.sm),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Gap($styles.insets.sm),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -125,7 +125,7 @@ class _TabBtn extends StatelessWidget {
|
|||||||
final iconImgPath = '${ImagePaths.common}/tab-$iconImg${selected ? '-active' : ''}.png';
|
final iconImgPath = '${ImagePaths.common}/tab-$iconImg${selected ? '-active' : ''}.png';
|
||||||
String tabLabel = localizations.tabLabel(tabIndex: index + 1, tabCount: tabController.length);
|
String tabLabel = localizations.tabLabel(tabIndex: index + 1, tabCount: tabController.length);
|
||||||
tabLabel = '$label: $tabLabel';
|
tabLabel = '$label: $tabLabel';
|
||||||
final double btnWidth = (context.widthPx / 6).clamp(80, 120);
|
final double btnWidth = (context.widthPx / 6).clamp(70, 120);
|
||||||
return MergeSemantics(
|
return MergeSemantics(
|
||||||
child: Semantics(
|
child: Semantics(
|
||||||
selected: selected,
|
selected: selected,
|
||||||
@ -136,25 +136,8 @@ class _TabBtn extends StatelessWidget {
|
|||||||
onPressed: () => tabController.index = index,
|
onPressed: () => tabController.index = index,
|
||||||
semanticLabel: label,
|
semanticLabel: label,
|
||||||
minimumSize: Size(btnWidth, 0),
|
minimumSize: Size(btnWidth, 0),
|
||||||
child: Stack(
|
// Image icon
|
||||||
children: [
|
child: Image.asset(iconImgPath, height: 32, width: 32, color: selected ? null : color),
|
||||||
/// Image icon
|
|
||||||
Image.asset(iconImgPath, height: 32, width: 32, color: selected ? null : color),
|
|
||||||
// if (selected)
|
|
||||||
// Positioned.fill(
|
|
||||||
// child: BottomCenter(
|
|
||||||
// child: Transform.translate(
|
|
||||||
// offset: Offset(0, $styles.insets.xxs),
|
|
||||||
// child: Animate().custom(
|
|
||||||
// curve: Curves.easeOutCubic,
|
|
||||||
// end: 24,
|
|
||||||
// builder: (_, v, __) => Container(height: 3, width: v, color: $styles.colors.accent1),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1149,10 +1149,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: string_scanner
|
name: string_scanner
|
||||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.1.1"
|
||||||
sync_http:
|
sync_http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1173,10 +1173,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
|
sha256: c9aba3b3dbfe8878845dfab5fa096eb8de7b62231baeeb1cea8e3ee81ca8c6d8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.16"
|
version: "0.4.15"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user