mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Fix sample index deployment action (#862)
* Update sample index dependencies * Update to tuneup 0.3.8, update dependencies * Upgrade to null safety, lock sass version * fix analyzer warnings * Fix unit tests * Fix issues from upgrading to null safety
This commit is contained in:
@@ -12,7 +12,7 @@ import 'package:html/parser.dart' show parse;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class CookbookScraper {
|
||||
WebDriver _driver;
|
||||
late WebDriver _driver;
|
||||
|
||||
Future init() async {
|
||||
_driver = await createDriver(desired: <String, dynamic>{});
|
||||
@@ -36,7 +36,12 @@ class CookbookScraper {
|
||||
await _driver.get(Uri.parse(url));
|
||||
var pageContent = await _driver.pageSource;
|
||||
var page = parse(pageContent);
|
||||
var name = page.querySelector('main>.container>header>h1').text;
|
||||
var search = 'main>.container>header>h1';
|
||||
var h1 = page.querySelector(search);
|
||||
if (h1 == null) {
|
||||
throw ('Could not find match for $search on page $url');
|
||||
}
|
||||
var name = h1.text;
|
||||
var description = page.querySelectorAll('main>.container>p').first.text;
|
||||
|
||||
var urlSegments = Uri.parse(url).pathSegments;
|
||||
@@ -50,6 +55,7 @@ class CookbookScraper {
|
||||
screenshots: [Screenshot(screenshotPath(url), 'Cookbook article')],
|
||||
tags: ['cookbook', category],
|
||||
source: url,
|
||||
difficulty: 'advanced',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,10 @@ Future<List<Sample>> getSamples() async {
|
||||
var cookbookFile = File('lib/src/cookbook.json');
|
||||
var contents = await yamlFile.readAsString();
|
||||
var cookbookContents = await cookbookFile.readAsString();
|
||||
var index = checkedYamlDecode(contents, (m) => Index.fromJson(m),
|
||||
var index = checkedYamlDecode(
|
||||
contents, (m) => m != null ? Index.fromJson(m) : null,
|
||||
sourceUrl: yamlFile.uri);
|
||||
if (index == null) throw('unable to get load from ${yamlFile.uri}');
|
||||
var cookbookIndex =
|
||||
Index.fromJson(json.decode(cookbookContents) as Map<dynamic, dynamic>);
|
||||
return index.samples..addAll(cookbookIndex.samples);
|
||||
|
||||
@@ -7,14 +7,15 @@ import 'dart:html';
|
||||
class Carousel {
|
||||
final bool withArrowKeyControl;
|
||||
|
||||
final Element container = querySelector('.slider-container');
|
||||
final Element container = querySelector('.slider-container')!;
|
||||
final List<Element> slides = querySelectorAll('.slider-single');
|
||||
|
||||
int currentSlideIndex, lastSlideIndex;
|
||||
late int currentSlideIndex;
|
||||
late int lastSlideIndex;
|
||||
|
||||
Element prevSlide, currentSlide, nextSlide;
|
||||
late Element prevSlide, currentSlide, nextSlide;
|
||||
|
||||
num x0;
|
||||
late num x0;
|
||||
bool touched = false;
|
||||
|
||||
Carousel.init({this.withArrowKeyControl = false}) {
|
||||
@@ -90,13 +91,13 @@ class Carousel {
|
||||
}
|
||||
|
||||
void _touchStartListener(TouchEvent e) {
|
||||
x0 = e.changedTouches.first.client.x;
|
||||
x0 = e.changedTouches!.first.client.x;
|
||||
touched = true;
|
||||
}
|
||||
|
||||
void _touchEndListener(TouchEvent e) {
|
||||
if (touched) {
|
||||
int dx = (e.changedTouches.first.client.x - x0) as int;
|
||||
int dx = (e.changedTouches!.first.client.x - x0) as int;
|
||||
|
||||
// dx==0 case is ignored
|
||||
if (dx > 0 && currentSlideIndex > 0) {
|
||||
@@ -115,7 +116,7 @@ class Carousel {
|
||||
|
||||
void _updateBullets() {
|
||||
final bullets =
|
||||
querySelector('.bullet-container').querySelectorAll('.bullet');
|
||||
querySelector('.bullet-container')!.querySelectorAll('.bullet');
|
||||
for (var i = 0; i < bullets.length; i++) {
|
||||
bullets[i].classes.remove('active');
|
||||
if (i == currentSlideIndex) {
|
||||
@@ -132,18 +133,18 @@ class Carousel {
|
||||
if (currentSlideIndex == slides.length - 1) {
|
||||
slides[0].classes.add('hidden');
|
||||
slides[slides.length - 1].classes.remove('hidden');
|
||||
prevArrow.classes.remove('hidden');
|
||||
nextArrow.classes.add('hidden');
|
||||
prevArrow!.classes.remove('hidden');
|
||||
nextArrow!.classes.add('hidden');
|
||||
} else if (currentSlideIndex == 0) {
|
||||
slides[slides.length - 1].classes.add('hidden');
|
||||
slides[0].classes.remove('hidden');
|
||||
prevArrow.classes.add('hidden');
|
||||
nextArrow.classes.remove('hidden');
|
||||
prevArrow!.classes.add('hidden');
|
||||
nextArrow!.classes.remove('hidden');
|
||||
} else {
|
||||
slides[slides.length - 1].classes.remove('hidden');
|
||||
slides[0].classes.remove('hidden');
|
||||
prevArrow.classes.remove('hidden');
|
||||
nextArrow.classes.remove('hidden');
|
||||
prevArrow!.classes.remove('hidden');
|
||||
nextArrow!.classes.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class Sample {
|
||||
final String name;
|
||||
|
||||
/// The author of the sample. Typically "Flutter"
|
||||
final String author;
|
||||
final String? author;
|
||||
|
||||
/// Screenshots of the sample or cookbook article. At least 1 screenshot is
|
||||
/// required.
|
||||
@@ -44,14 +44,14 @@ class Sample {
|
||||
final String source;
|
||||
|
||||
/// A link to this sample running in the browser.
|
||||
final String web;
|
||||
final String? web;
|
||||
|
||||
/// 3-5 sentences describing the sample.
|
||||
final String description;
|
||||
|
||||
/// The difficulty level. Values are either 'beginner', 'intermediate', or
|
||||
/// 'advanced'.
|
||||
final String difficulty;
|
||||
final String? difficulty;
|
||||
|
||||
/// List of widgets or Flutter APIs used by the sample. e.g. "AnimatedBuilder"
|
||||
/// or "ChangeNotifier".
|
||||
@@ -76,26 +76,26 @@ class Sample {
|
||||
final String type;
|
||||
|
||||
/// The date this sample was created.
|
||||
final DateTime date;
|
||||
final DateTime? date;
|
||||
|
||||
/// The Flutter channel this sample runs on. Either 'stable', 'dev' or
|
||||
/// 'master'.
|
||||
final String channel;
|
||||
final String? channel;
|
||||
|
||||
Sample({
|
||||
this.name,
|
||||
this.author,
|
||||
this.screenshots,
|
||||
this.source,
|
||||
required this.name,
|
||||
this.author = 'Flutter',
|
||||
required this.screenshots,
|
||||
required this.source,
|
||||
this.web,
|
||||
this.description,
|
||||
this.difficulty,
|
||||
required this.description,
|
||||
this.difficulty = 'beginner',
|
||||
this.widgets = const [],
|
||||
this.packages = const [],
|
||||
this.tags = const [],
|
||||
this.platforms = const [],
|
||||
this.links = const [],
|
||||
this.type,
|
||||
required this.type,
|
||||
this.date,
|
||||
this.channel,
|
||||
});
|
||||
|
||||
@@ -12,9 +12,9 @@ Index _$IndexFromJson(Map json) {
|
||||
$checkedConvert(
|
||||
json,
|
||||
'samples',
|
||||
(v) => (v as List)
|
||||
?.map((e) => e == null ? null : Sample.fromJson(e as Map))
|
||||
?.toList()),
|
||||
(v) => (v as List<dynamic>)
|
||||
.map((e) => Sample.fromJson(e as Map))
|
||||
.toList()),
|
||||
);
|
||||
return val;
|
||||
});
|
||||
@@ -28,35 +28,35 @@ Sample _$SampleFromJson(Map json) {
|
||||
return $checkedNew('Sample', json, () {
|
||||
final val = Sample(
|
||||
name: $checkedConvert(json, 'name', (v) => v as String),
|
||||
author: $checkedConvert(json, 'author', (v) => v as String),
|
||||
author: $checkedConvert(json, 'author', (v) => v as String?),
|
||||
screenshots: $checkedConvert(
|
||||
json,
|
||||
'screenshots',
|
||||
(v) => (v as List)
|
||||
?.map((e) => e == null ? null : Screenshot.fromJson(e as Map))
|
||||
?.toList()),
|
||||
(v) => (v as List<dynamic>)
|
||||
.map((e) => Screenshot.fromJson(e as Map))
|
||||
.toList()),
|
||||
source: $checkedConvert(json, 'source', (v) => v as String),
|
||||
web: $checkedConvert(json, 'web', (v) => v as String),
|
||||
web: $checkedConvert(json, 'web', (v) => v as String?),
|
||||
description: $checkedConvert(json, 'description', (v) => v as String),
|
||||
difficulty: $checkedConvert(json, 'difficulty', (v) => v as String),
|
||||
difficulty: $checkedConvert(json, 'difficulty', (v) => v as String?),
|
||||
widgets: $checkedConvert(json, 'widgets',
|
||||
(v) => (v as List)?.map((e) => e as String)?.toList()),
|
||||
(v) => (v as List<dynamic>).map((e) => e as String).toList()),
|
||||
packages: $checkedConvert(json, 'packages',
|
||||
(v) => (v as List)?.map((e) => e as String)?.toList()),
|
||||
tags: $checkedConvert(
|
||||
json, 'tags', (v) => (v as List)?.map((e) => e as String)?.toList()),
|
||||
(v) => (v as List<dynamic>).map((e) => e as String).toList()),
|
||||
tags: $checkedConvert(json, 'tags',
|
||||
(v) => (v as List<dynamic>).map((e) => e as String).toList()),
|
||||
platforms: $checkedConvert(json, 'platforms',
|
||||
(v) => (v as List)?.map((e) => e as String)?.toList()),
|
||||
(v) => (v as List<dynamic>).map((e) => e as String).toList()),
|
||||
links: $checkedConvert(
|
||||
json,
|
||||
'links',
|
||||
(v) => (v as List)
|
||||
?.map((e) => e == null ? null : Link.fromJson(e as Map))
|
||||
?.toList()),
|
||||
(v) => (v as List<dynamic>)
|
||||
.map((e) => Link.fromJson(e as Map))
|
||||
.toList()),
|
||||
type: $checkedConvert(json, 'type', (v) => v as String),
|
||||
date: $checkedConvert(
|
||||
json, 'date', (v) => v == null ? null : DateTime.parse(v as String)),
|
||||
channel: $checkedConvert(json, 'channel', (v) => v as String),
|
||||
channel: $checkedConvert(json, 'channel', (v) => v as String?),
|
||||
);
|
||||
return val;
|
||||
});
|
||||
|
||||
@@ -83,6 +83,7 @@ samples:
|
||||
- scoped_model
|
||||
tags: ['intermediate', 'sample', 'gallery', 'material', 'design', 'vignettes']
|
||||
platforms: ['web', 'ios', 'android']
|
||||
links: []
|
||||
type: demo
|
||||
|
||||
- name: Add to App
|
||||
@@ -105,6 +106,7 @@ samples:
|
||||
- provider
|
||||
tags: ['advanced', 'sample', 'add-to-app', 'android', 'ios', 'native', 'embedding']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Animations
|
||||
@@ -133,6 +135,7 @@ samples:
|
||||
- flutter/material
|
||||
tags: ['intermediate', 'sample', 'animation']
|
||||
platforms: ['ios', 'android', 'web']
|
||||
links: []
|
||||
type: sample
|
||||
web: web/animations
|
||||
|
||||
@@ -157,6 +160,7 @@ samples:
|
||||
- google_maps_webservice
|
||||
tags: ['intermediate', 'sample', 'firebase', 'maps']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Isolate Example
|
||||
@@ -181,6 +185,7 @@ samples:
|
||||
- dart:math
|
||||
tags: ['intermediate', 'sample', 'isolates', 'concurrency']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: jsonexample
|
||||
@@ -209,6 +214,7 @@ samples:
|
||||
- built_value_generator
|
||||
tags: ['beginner', 'sample']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Place Tracker
|
||||
@@ -235,6 +241,7 @@ samples:
|
||||
- google_maps_flutter
|
||||
tags: ['intermediate', 'sample', 'json', 'serialization']
|
||||
platforms: ['android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Platform Design
|
||||
@@ -266,6 +273,7 @@ samples:
|
||||
- flutter/cupertino
|
||||
tags: ['advanced', 'sample', 'ios']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Platform View Swift
|
||||
@@ -287,6 +295,7 @@ samples:
|
||||
- flutter/services
|
||||
tags: ['advanced', 'sample', 'ios']
|
||||
platforms: ['ios']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Infinite List
|
||||
@@ -311,6 +320,7 @@ samples:
|
||||
- meta
|
||||
tags: ['sample', 'material', 'design', 'android', 'ios']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: IOS App Clip
|
||||
@@ -331,6 +341,7 @@ samples:
|
||||
- device_info
|
||||
tags: ['sample', 'Device Info', 'ios']
|
||||
platforms: ['ios']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Testing App
|
||||
@@ -353,6 +364,7 @@ samples:
|
||||
- provider
|
||||
tags: ['sample', 'material', 'android', 'ios']
|
||||
platforms: ['ios', 'android']
|
||||
links: []
|
||||
type: sample
|
||||
|
||||
- name: Provider Shopper
|
||||
@@ -376,6 +388,7 @@ samples:
|
||||
- provider
|
||||
tags: ['intermediate', 'sample', 'provider']
|
||||
platforms: ['ios', 'android', 'web']
|
||||
links: []
|
||||
type: sample
|
||||
web: web/provider_shopper
|
||||
|
||||
@@ -402,6 +415,7 @@ samples:
|
||||
- firebase
|
||||
tags: ['intermediate', 'sample', 'firebase']
|
||||
platforms: ['ios', 'android', 'web']
|
||||
links: []
|
||||
type: sample
|
||||
web: web/web_dashboard
|
||||
|
||||
@@ -423,6 +437,7 @@ samples:
|
||||
packages: []
|
||||
tags: ['intermediate', 'sample', 'forms']
|
||||
platforms: ['ios', 'android', 'web']
|
||||
links: []
|
||||
type: sample
|
||||
web: web/form_app
|
||||
###################
|
||||
@@ -433,6 +448,7 @@ samples:
|
||||
author: Flutter
|
||||
screenshots:
|
||||
- url: images/charts1.png
|
||||
alt: Charts screenshot
|
||||
source: https://github.com/google/charts
|
||||
description: >
|
||||
A general-purpose charting library.
|
||||
@@ -440,6 +456,7 @@ samples:
|
||||
widgets: []
|
||||
packages: []
|
||||
platforms: ['ios', 'android', 'web']
|
||||
links: []
|
||||
tags: ['demo', 'charts']
|
||||
web: web/charts
|
||||
type: demo
|
||||
@@ -456,6 +473,7 @@ samples:
|
||||
widgets: []
|
||||
packages: []
|
||||
platforms: ['web']
|
||||
links: []
|
||||
tags: ['demo', 'flutter create']
|
||||
web: web/filipino_cuisine
|
||||
type: demo
|
||||
@@ -472,6 +490,7 @@ samples:
|
||||
widgets: []
|
||||
packages: []
|
||||
platforms: ['web']
|
||||
links: []
|
||||
tags: ['demo', 'data', 'visualization']
|
||||
web: web/github_dataviz
|
||||
type: demo
|
||||
@@ -488,6 +507,7 @@ samples:
|
||||
widgets: []
|
||||
packages: []
|
||||
platforms: ['web']
|
||||
links: []
|
||||
tags: ['demo', 'animation']
|
||||
web: web/particle_background
|
||||
type: demo
|
||||
@@ -504,6 +524,7 @@ samples:
|
||||
widgets: []
|
||||
packages: []
|
||||
platforms: ['web']
|
||||
links: []
|
||||
tags: ['demo', 'game']
|
||||
web: web/slide_puzzle
|
||||
type: demo
|
||||
@@ -520,6 +541,7 @@ samples:
|
||||
widgets: []
|
||||
packages: []
|
||||
platforms: ['web']
|
||||
links: []
|
||||
tags: ['demo', 'animation']
|
||||
web: https://z.flutter.gallery/#/dice
|
||||
type: demo
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file
|
||||
|
||||
bool matchesQuery(String query, String sampleAttributes) {
|
||||
if (query == null || query.isEmpty) {
|
||||
if (query.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
var queryWords = query.split(' ')..removeWhere((s) => s.isEmpty);
|
||||
@@ -68,11 +68,13 @@ String searchQueryFromParams(Map<String, String> params) {
|
||||
}
|
||||
if (params.containsKey('type')) {
|
||||
if (buf.isNotEmpty) buf.write(' ');
|
||||
buf.write('type:' + params['type']);
|
||||
var value = params['type'];
|
||||
if (value != null) buf.write('type:' + value);
|
||||
}
|
||||
if (params.containsKey('platform')) {
|
||||
if (buf.isNotEmpty) buf.write(' ');
|
||||
buf.write('platform:' + params['platform']);
|
||||
var value = params['platform'];
|
||||
if (value != null) buf.write('platform:' + value);
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
|
||||
@@ -187,7 +187,7 @@ String _descriptionPage(Sample sample) => '''
|
||||
|
||||
String _descriptionButtons(Sample sample) {
|
||||
var buf = StringBuffer();
|
||||
if (sample?.web?.isNotEmpty == true) {
|
||||
if (sample.web?.isNotEmpty == true) {
|
||||
buf.write(
|
||||
'''<button class="mdc-button mdc-button--outlined" onclick="window.location.href = '${sample.web}';"><span class="mdc-button__ripple"></span> Launch App</button>''');
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ String pascalCase(String input) {
|
||||
|
||||
String _fixCase(String input, String separator) =>
|
||||
input.replaceAllMapped(_upperCase, (match) {
|
||||
var lower = match.group(0).toLowerCase();
|
||||
var group = match.group(0);
|
||||
if (group == null) return input;
|
||||
var lower = group.toLowerCase();
|
||||
|
||||
if (match.start > 0) {
|
||||
lower = '$separator$lower';
|
||||
|
||||
@@ -4,23 +4,29 @@ homepage: https://github.com/flutter/samples_index
|
||||
author: Flutter Team <flutter-dev@googlegroups.com>
|
||||
version: 0.0.1
|
||||
environment:
|
||||
sdk: ">=2.5.0 <3.0.0"
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
dependencies:
|
||||
json_annotation: ^3.0.0
|
||||
json_annotation: ^4.0.1
|
||||
path: ^1.6.0
|
||||
yaml: ^2.2.0
|
||||
mdc_web: ^0.5.0-pre
|
||||
yaml: ^3.0.0
|
||||
mdc_web: ^0.6.0
|
||||
sass_builder: ^2.1.0
|
||||
checked_yaml: ^1.0.0
|
||||
webdriver: ^2.1.0
|
||||
html: ^0.14.0
|
||||
checked_yaml: ^2.0.1
|
||||
webdriver: ^3.0.0
|
||||
html: ^0.15.0
|
||||
dev_dependencies:
|
||||
grinder: ^0.8.3
|
||||
grinder: ^0.9.0
|
||||
flutter_lints: ^1.0.0
|
||||
test: ^1.6.0
|
||||
json_serializable: ^3.2.0
|
||||
build: ^1.2.0
|
||||
build_runner: ^1.7.0
|
||||
build_web_compilers: ^2.7.0
|
||||
tuneup: ^0.3.6
|
||||
image: ^2.1.0
|
||||
test: ^1.17.10
|
||||
json_serializable: ^4.0.2
|
||||
build: ^2.0.3
|
||||
build_runner: ^2.0.6
|
||||
build_web_compilers: ^3.0.0
|
||||
tuneup: ^0.3.8
|
||||
image: ^3.0.2
|
||||
# waiting for the next material-components-web release.
|
||||
# Once released, it will need to be rolled into package:mdc_web.
|
||||
#
|
||||
# https://github.com/material-components/material-components-web/pull/7158
|
||||
dependency_overrides:
|
||||
sass: 1.32.10
|
||||
@@ -16,15 +16,18 @@ void main() {
|
||||
var contents = await file.readAsString();
|
||||
expect(contents, isNotEmpty);
|
||||
|
||||
var index = checkedYamlDecode(contents, (m) => Index.fromJson(m),
|
||||
var index = checkedYamlDecode(contents, (m) => m != null ? Index.fromJson(m) : null,
|
||||
sourceUrl: file.uri);
|
||||
if (index == null) {
|
||||
throw('unable to load YAML from $file');
|
||||
}
|
||||
expect(index.samples, isNotEmpty);
|
||||
|
||||
var sample = index.samples.first;
|
||||
expect(sample, isNotNull);
|
||||
expect(sample.name, 'Kittens');
|
||||
expect(sample.screenshots, hasLength(2));
|
||||
expect(sample.source, 'http://github.com/johnpryan/kittens');
|
||||
expect(sample.source, 'https://github.com/johnpryan/kittens');
|
||||
expect(sample.description, 'A sample kitten app');
|
||||
expect(sample.difficulty, 'beginner');
|
||||
expect(sample.widgets, hasLength(2));
|
||||
@@ -36,7 +39,7 @@ void main() {
|
||||
expect(sample.platforms, hasLength(3));
|
||||
expect(sample.links, hasLength(2));
|
||||
expect(sample.links[1].text, 'author');
|
||||
expect(sample.links[1].href, 'http://jpryan.me');
|
||||
expect(sample.links[1].href, 'https://jpryan.me');
|
||||
expect(sample.type, 'sample');
|
||||
expect(sample.date, DateTime.parse('2019-12-15T02:59:43.1Z'));
|
||||
expect(sample.channel, 'stable');
|
||||
@@ -49,8 +52,11 @@ void main() {
|
||||
var contents = await file.readAsString();
|
||||
expect(contents, isNotEmpty);
|
||||
|
||||
var index = checkedYamlDecode(contents, (m) => Index.fromJson(m),
|
||||
var index = checkedYamlDecode(contents, (m) => m != null ? Index.fromJson(m) : null,
|
||||
sourceUrl: file.uri);
|
||||
if (index == null) {
|
||||
throw('unable to load YAML from $file');
|
||||
}
|
||||
var sample = index.samples.first;
|
||||
expect(
|
||||
sample.searchAttributes.split(' '),
|
||||
|
||||
@@ -5,7 +5,7 @@ samples:
|
||||
alt: a kitten
|
||||
- url: https://placekitten.com/400/400
|
||||
alt: another kitten
|
||||
source: http://github.com/johnpryan/kittens
|
||||
source: https://github.com/johnpryan/kittens
|
||||
description: A sample kitten app
|
||||
difficulty: beginner
|
||||
widgets:
|
||||
@@ -20,7 +20,7 @@ samples:
|
||||
- text: inspiration
|
||||
href: https://apps.apple.com/us/app/neko-atsume-kitty-collector/id923917775
|
||||
- text: author
|
||||
href: http://jpryan.me
|
||||
href: https://jpryan.me
|
||||
type: sample # sample, app, or cookbook
|
||||
date: 2019-12-15T02:59:43.1Z
|
||||
channel: stable
|
||||
|
||||
@@ -104,12 +104,11 @@ Future<void> _createThumbnails(Directory directory) async {
|
||||
continue;
|
||||
}
|
||||
|
||||
var file = entity as File;
|
||||
var pathPrefix = path.dirname(file.path);
|
||||
var pathPrefix = path.dirname(entity.path);
|
||||
var thumbnailFile = File(path.join(pathPrefix, filename + '_thumb.png'));
|
||||
|
||||
var img = image.decodeImage(await file.readAsBytes());
|
||||
var resized = image.copyResize(img, width: 640);
|
||||
var img = image.decodeImage(await entity.readAsBytes());
|
||||
var resized = image.copyResize(img!, width: 640);
|
||||
filesToWrite.add(thumbnailFile.writeAsBytes(image.encodePng(resized)));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ import 'dart:html';
|
||||
import 'package:mdc_web/mdc_web.dart';
|
||||
import 'package:samples_index/src/carousel.dart';
|
||||
|
||||
InputElement searchInput;
|
||||
|
||||
void main() {
|
||||
querySelectorAll('.mdc-card__primary-action').forEach((el) => MDCRipple(el));
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import 'package:mdc_web/mdc_web.dart';
|
||||
import 'package:samples_index/browser.dart';
|
||||
|
||||
/// The Material text input for searching
|
||||
MDCTextField searchBar;
|
||||
MDCChipSet chipSet;
|
||||
late final MDCTextField searchBar;
|
||||
late final MDCChipSet chipSet;
|
||||
|
||||
/// The current set of query parameters that determine how the cards are
|
||||
/// filtered. e.g. {'search': 'kittens', 'platform': 'ios'}
|
||||
@@ -16,9 +16,9 @@ const platformKey = 'platform';
|
||||
|
||||
void main() {
|
||||
// Initialize Material components
|
||||
MDCFloatingLabel(querySelector('.mdc-floating-label'));
|
||||
searchBar = MDCTextField(querySelector('#search-bar'));
|
||||
MDCRipple(querySelector('#clear-button'));
|
||||
MDCFloatingLabel(querySelector('.mdc-floating-label')!);
|
||||
searchBar = MDCTextField(querySelector('#search-bar')!);
|
||||
MDCRipple(querySelector('#clear-button')!);
|
||||
|
||||
// Listen for hash changes
|
||||
window.onHashChange.listen((_) {
|
||||
@@ -33,7 +33,7 @@ void main() {
|
||||
querySelectorAll('.mdc-card__primary-action').forEach((el) => MDCRipple(el)
|
||||
// Navigate to the description page when tapped
|
||||
..listen('click', (e) {
|
||||
window.location.href = el.attributes['href'];
|
||||
window.location.href = el.attributes['href']!;
|
||||
}));
|
||||
|
||||
// Filter cards on each keypress
|
||||
@@ -44,12 +44,12 @@ void main() {
|
||||
|
||||
// Update the URL only when the user is done typing in the search bar
|
||||
searchBar.listen('change', (e) {
|
||||
queryParams[searchKey] = searchBar.value;
|
||||
queryParams[searchKey] = searchBar.value!;
|
||||
updateHash();
|
||||
});
|
||||
|
||||
// Update the hash, cards, and text input when the clear button is pressed
|
||||
querySelector('#clear-button').onClick.listen((e) {
|
||||
querySelector('#clear-button')!.onClick.listen((e) {
|
||||
queryParams.remove('search');
|
||||
updateHash();
|
||||
setSearchBarText();
|
||||
@@ -57,10 +57,10 @@ void main() {
|
||||
});
|
||||
|
||||
// Initialize chips
|
||||
chipSet = MDCChipSet(querySelector('.mdc-chip-set'));
|
||||
chipSet = MDCChipSet(querySelector('.mdc-chip-set')!);
|
||||
chipSet.listen('MDCChip:selection', (e) {
|
||||
// Get the query parameters for this chip
|
||||
var selectedChipIndex = chipSet.chips.indexWhere((chip) => chip.selected);
|
||||
var selectedChipIndex = chipSet.chips.indexWhere((chip) => chip.selected!);
|
||||
var chipParams = paramsForChip(selectedChipIndex);
|
||||
|
||||
// Overwrite query parameters with new ones
|
||||
@@ -89,7 +89,7 @@ void setSearchBarText() {
|
||||
|
||||
void setSelectedChips() {
|
||||
var type = queryParams.containsKey(typeKey) ? queryParams[typeKey] : '';
|
||||
if (type.isNotEmpty) {
|
||||
if (type!.isNotEmpty) {
|
||||
if (type == 'sample') {
|
||||
chipSet.chips[1].selected = true;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ void setSelectedChips() {
|
||||
// Apply the platform from the hash in the URL
|
||||
var platform =
|
||||
queryParams.containsKey(platformKey) ? queryParams[platformKey] : '';
|
||||
if (platform.isNotEmpty) {
|
||||
if (platform!.isNotEmpty) {
|
||||
if (platform == 'web') {
|
||||
chipSet.chips[3].selected = true;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ void setSelectedChips() {
|
||||
|
||||
void handleSearch() {
|
||||
var search = searchBar.value;
|
||||
queryParams[searchKey] = search;
|
||||
queryParams[searchKey] = search!;
|
||||
filterCards();
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void filterCards() {
|
||||
var elements = querySelectorAll('[search-attrs]');
|
||||
for (var element in elements) {
|
||||
var searchAttributes = element.attributes['search-attrs'];
|
||||
if (matchesQuery(searchQuery, searchAttributes)) {
|
||||
if (matchesQuery(searchQuery, searchAttributes!)) {
|
||||
element.hidden = false;
|
||||
} else {
|
||||
element.hidden = true;
|
||||
|
||||
Reference in New Issue
Block a user