1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-13 10:59:04 +00:00

Desktop photo search (#174)

This commit is contained in:
Brett Morgan
2019-12-11 07:22:42 +11:00
committed by GitHub
parent 8c27a25d50
commit f07b4a90d5
74 changed files with 7380 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:file_chooser/file_chooser.dart' as file_choser;
import 'package:logging/logging.dart';
import 'package:menubar/menubar.dart' as menubar;
import 'package:meta/meta.dart';
import 'package:provider/provider.dart';
import 'src/model/photo_search_model.dart';
import 'src/unsplash/unsplash.dart';
import 'src/widgets/data_tree.dart';
import 'src/widgets/photo_details.dart';
import 'src/widgets/photo_search_dialog.dart';
import 'src/widgets/split.dart';
import 'unsplash_access_key.dart';
void main() {
Logger.root.level = Level.ALL;
Logger.root.onRecord.listen((rec) {
// ignore: avoid_print
print('${rec.loggerName} ${rec.level.name}: ${rec.time}: ${rec.message}');
});
if (unsplashAccessKey.isEmpty) {
Logger('main').severe('Unsplash Access Key is required. '
'Please add to `lib/unsplash_access_key.dart`.');
exit(1);
}
runApp(
ChangeNotifierProvider<PhotoSearchModel>(
create: (context) => PhotoSearchModel(
Unsplash(accessKey: unsplashAccessKey),
),
child: UnsplashSearchApp(),
),
);
}
class UnsplashSearchApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Photo Search',
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: const UnsplashHomePage(title: 'Photo Search'),
);
}
}
class UnsplashHomePage extends StatelessWidget {
const UnsplashHomePage({@required this.title});
final String title;
@override
Widget build(BuildContext context) {
final photoSearchModel = Provider.of<PhotoSearchModel>(context);
menubar.setApplicationMenu([
menubar.Submenu(label: 'Search', children: [
menubar.MenuItem(
label: 'Search ...',
onClicked: () {
showDialog<void>(
context: context,
builder: (context) =>
PhotoSearchDialog(photoSearchModel.addSearch),
);
},
),
])
]);
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: photoSearchModel.entries.isNotEmpty
? Split(
axis: Axis.horizontal,
initialFirstFraction: 0.4,
firstChild: DataTree(photoSearchModel.entries),
secondChild: Center(
child: photoSearchModel.selectedPhoto != null
? PhotoDetails(
photo: photoSearchModel.selectedPhoto,
onPhotoSave: (photo) async {
final result = await file_choser.showSavePanel(
suggestedFileName: '${photo.id}.jpg',
allowedFileTypes: ['jpg'],
);
if (!result.canceled) {
final bytes =
await photoSearchModel.download(photo: photo);
await File(result.paths[0]).writeAsBytes(bytes);
}
},
)
: Container(),
),
)
: const Center(
child: Text('Search for Photos using the Fab button'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => showDialog<void>(
context: context,
builder: (context) => PhotoSearchDialog(photoSearchModel.addSearch),
),
tooltip: 'Search for a photo',
child: Icon(Icons.search),
),
);
}
}

View File

@@ -0,0 +1,72 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';
import '../unsplash/photo.dart';
import '../unsplash/unsplash.dart';
import '../widgets/data_tree.dart' show Entry;
import 'search.dart';
class _PhotoEntry extends Entry {
_PhotoEntry(this._photo, this._model) : super('Photo by ${_photo.user.name}');
final Photo _photo;
final PhotoSearchModel _model;
@override
bool get isSelected => false;
@override
set isSelected(bool selected) {
_model._setSelectedPhoto(_photo);
}
}
class _SearchEntry extends Entry {
_SearchEntry(String query, List<Photo> photos, PhotoSearchModel model)
: super(
query,
List<Entry>.unmodifiable(
photos.map<Entry>((photo) => _PhotoEntry(photo, model)),
),
);
}
class PhotoSearchModel extends ChangeNotifier {
PhotoSearchModel(this._client);
final Unsplash _client;
List<Entry> get entries => List.unmodifiable(_entries);
final List<Entry> _entries = <Entry>[];
Photo get selectedPhoto => _selectedPhoto;
void _setSelectedPhoto(Photo photo) {
_selectedPhoto = photo;
notifyListeners();
}
Photo _selectedPhoto;
Future<void> addSearch(String query) async {
final result = await _client.searchPhotos(
query: query,
orientation: SearchPhotosOrientation.portrait,
);
final search = Search((s) {
s
..query = query
..results.addAll(result.results);
});
_entries.add(_SearchEntry(query, search.results.toList(), this));
notifyListeners();
}
Future<Uint8List> download({@required Photo photo}) =>
_client.download(photo);
}

View File

@@ -0,0 +1,36 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
import '../unsplash/photo.dart';
part 'search.g.dart';
abstract class Search implements Built<Search, SearchBuilder> {
factory Search([void Function(SearchBuilder) updates]) = _$Search;
Search._();
@BuiltValueField(wireName: 'query')
String get query;
@BuiltValueField(wireName: 'results')
BuiltList<Photo> get results;
String toJson() {
return json.encode(serializers.serializeWith(Search.serializer, this));
}
static Search fromJson(String jsonString) {
return serializers.deserializeWith(
Search.serializer, json.decode(jsonString));
}
static Serializer<Search> get serializer => _$searchSerializer;
}

View File

@@ -0,0 +1,167 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'search.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Search> _$searchSerializer = new _$SearchSerializer();
class _$SearchSerializer implements StructuredSerializer<Search> {
@override
final Iterable<Type> types = const [Search, _$Search];
@override
final String wireName = 'Search';
@override
Iterable<Object> serialize(Serializers serializers, Search object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'query',
serializers.serialize(object.query,
specifiedType: const FullType(String)),
'results',
serializers.serialize(object.results,
specifiedType:
const FullType(BuiltList, const [const FullType(Photo)])),
];
return result;
}
@override
Search deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new SearchBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'query':
result.query = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'results':
result.results.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(Photo)]))
as BuiltList<dynamic>);
break;
}
}
return result.build();
}
}
class _$Search extends Search {
@override
final String query;
@override
final BuiltList<Photo> results;
factory _$Search([void Function(SearchBuilder) updates]) =>
(new SearchBuilder()..update(updates)).build();
_$Search._({this.query, this.results}) : super._() {
if (query == null) {
throw new BuiltValueNullFieldError('Search', 'query');
}
if (results == null) {
throw new BuiltValueNullFieldError('Search', 'results');
}
}
@override
Search rebuild(void Function(SearchBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
SearchBuilder toBuilder() => new SearchBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Search && query == other.query && results == other.results;
}
@override
int get hashCode {
return $jf($jc($jc(0, query.hashCode), results.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Search')
..add('query', query)
..add('results', results))
.toString();
}
}
class SearchBuilder implements Builder<Search, SearchBuilder> {
_$Search _$v;
String _query;
String get query => _$this._query;
set query(String query) => _$this._query = query;
ListBuilder<Photo> _results;
ListBuilder<Photo> get results =>
_$this._results ??= new ListBuilder<Photo>();
set results(ListBuilder<Photo> results) => _$this._results = results;
SearchBuilder();
SearchBuilder get _$this {
if (_$v != null) {
_query = _$v.query;
_results = _$v.results?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(Search other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Search;
}
@override
void update(void Function(SearchBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Search build() {
_$Search _$result;
try {
_$result = _$v ?? new _$Search._(query: query, results: results.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'results';
results.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'Search', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,27 @@
// Copyright 2019 The Flutter team. 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:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
import 'package:built_collection/built_collection.dart';
import 'model/search.dart';
import 'unsplash/api_error.dart';
import 'unsplash/current_user_collections.dart';
import 'unsplash/exif.dart';
import 'unsplash/links.dart';
import 'unsplash/location.dart';
import 'unsplash/photo.dart';
import 'unsplash/position.dart';
import 'unsplash/search_photos_response.dart';
import 'unsplash/tags.dart';
import 'unsplash/urls.dart';
import 'unsplash/user.dart';
part 'serializers.g.dart';
//add all of the built value types that require serialization
@SerializersFor([Search, ApiError, Photo, SearchPhotosResponse])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

View File

@@ -0,0 +1,44 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'serializers.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializers _$serializers = (new Serializers().toBuilder()
..add(ApiError.serializer)
..add(CurrentUserCollections.serializer)
..add(Exif.serializer)
..add(Links.serializer)
..add(Location.serializer)
..add(Photo.serializer)
..add(Position.serializer)
..add(Search.serializer)
..add(SearchPhotosResponse.serializer)
..add(Tags.serializer)
..add(Urls.serializer)
..add(User.serializer)
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(Photo)]),
() => new ListBuilder<Photo>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(Photo)]),
() => new ListBuilder<Photo>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(String)]),
() => new ListBuilder<String>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(Tags)]),
() => new ListBuilder<Tags>())
..addBuilderFactory(
const FullType(
BuiltList, const [const FullType(CurrentUserCollections)]),
() => new ListBuilder<CurrentUserCollections>()))
.build();
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,33 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'api_error.g.dart';
abstract class ApiError implements Built<ApiError, ApiErrorBuilder> {
factory ApiError([void Function(ApiErrorBuilder) updates]) = _$ApiError;
ApiError._();
@BuiltValueField(wireName: 'errors')
BuiltList<String> get errors;
String toJson() {
return json.encode(serializers.serializeWith(ApiError.serializer, this));
}
static ApiError fromJson(String jsonString) {
return serializers.deserializeWith(
ApiError.serializer, json.decode(jsonString));
}
static Serializer<ApiError> get serializer => _$apiErrorSerializer;
}

View File

@@ -0,0 +1,148 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'api_error.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<ApiError> _$apiErrorSerializer = new _$ApiErrorSerializer();
class _$ApiErrorSerializer implements StructuredSerializer<ApiError> {
@override
final Iterable<Type> types = const [ApiError, _$ApiError];
@override
final String wireName = 'ApiError';
@override
Iterable<Object> serialize(Serializers serializers, ApiError object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'errors',
serializers.serialize(object.errors,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])),
];
return result;
}
@override
ApiError deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new ApiErrorBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'errors':
result.errors.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(String)]))
as BuiltList<dynamic>);
break;
}
}
return result.build();
}
}
class _$ApiError extends ApiError {
@override
final BuiltList<String> errors;
factory _$ApiError([void Function(ApiErrorBuilder) updates]) =>
(new ApiErrorBuilder()..update(updates)).build();
_$ApiError._({this.errors}) : super._() {
if (errors == null) {
throw new BuiltValueNullFieldError('ApiError', 'errors');
}
}
@override
ApiError rebuild(void Function(ApiErrorBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
ApiErrorBuilder toBuilder() => new ApiErrorBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is ApiError && errors == other.errors;
}
@override
int get hashCode {
return $jf($jc(0, errors.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('ApiError')..add('errors', errors))
.toString();
}
}
class ApiErrorBuilder implements Builder<ApiError, ApiErrorBuilder> {
_$ApiError _$v;
ListBuilder<String> _errors;
ListBuilder<String> get errors =>
_$this._errors ??= new ListBuilder<String>();
set errors(ListBuilder<String> errors) => _$this._errors = errors;
ApiErrorBuilder();
ApiErrorBuilder get _$this {
if (_$v != null) {
_errors = _$v.errors?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(ApiError other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$ApiError;
}
@override
void update(void Function(ApiErrorBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$ApiError build() {
_$ApiError _$result;
try {
_$result = _$v ?? new _$ApiError._(errors: errors.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'errors';
errors.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'ApiError', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,49 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'current_user_collections.g.dart';
abstract class CurrentUserCollections
implements Built<CurrentUserCollections, CurrentUserCollectionsBuilder> {
factory CurrentUserCollections(
[void Function(CurrentUserCollectionsBuilder) updates]) =
_$CurrentUserCollections;
CurrentUserCollections._();
@BuiltValueField(wireName: 'id')
int get id;
@nullable
@BuiltValueField(wireName: 'title')
String get title;
@nullable
@BuiltValueField(wireName: 'published_at')
String get publishedAt;
@nullable
@BuiltValueField(wireName: 'updated_at')
String get updatedAt;
String toJson() {
return json.encode(
serializers.serializeWith(CurrentUserCollections.serializer, this));
}
static CurrentUserCollections fromJson(String jsonString) {
return serializers.deserializeWith(
CurrentUserCollections.serializer, json.decode(jsonString));
}
static Serializer<CurrentUserCollections> get serializer =>
_$currentUserCollectionsSerializer;
}

View File

@@ -0,0 +1,208 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'current_user_collections.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<CurrentUserCollections> _$currentUserCollectionsSerializer =
new _$CurrentUserCollectionsSerializer();
class _$CurrentUserCollectionsSerializer
implements StructuredSerializer<CurrentUserCollections> {
@override
final Iterable<Type> types = const [
CurrentUserCollections,
_$CurrentUserCollections
];
@override
final String wireName = 'CurrentUserCollections';
@override
Iterable<Object> serialize(
Serializers serializers, CurrentUserCollections object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'id',
serializers.serialize(object.id, specifiedType: const FullType(int)),
];
if (object.title != null) {
result
..add('title')
..add(serializers.serialize(object.title,
specifiedType: const FullType(String)));
}
if (object.publishedAt != null) {
result
..add('published_at')
..add(serializers.serialize(object.publishedAt,
specifiedType: const FullType(String)));
}
if (object.updatedAt != null) {
result
..add('updated_at')
..add(serializers.serialize(object.updatedAt,
specifiedType: const FullType(String)));
}
return result;
}
@override
CurrentUserCollections deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new CurrentUserCollectionsBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'id':
result.id = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'title':
result.title = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'published_at':
result.publishedAt = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'updated_at':
result.updatedAt = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$CurrentUserCollections extends CurrentUserCollections {
@override
final int id;
@override
final String title;
@override
final String publishedAt;
@override
final String updatedAt;
factory _$CurrentUserCollections(
[void Function(CurrentUserCollectionsBuilder) updates]) =>
(new CurrentUserCollectionsBuilder()..update(updates)).build();
_$CurrentUserCollections._(
{this.id, this.title, this.publishedAt, this.updatedAt})
: super._() {
if (id == null) {
throw new BuiltValueNullFieldError('CurrentUserCollections', 'id');
}
}
@override
CurrentUserCollections rebuild(
void Function(CurrentUserCollectionsBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
CurrentUserCollectionsBuilder toBuilder() =>
new CurrentUserCollectionsBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is CurrentUserCollections &&
id == other.id &&
title == other.title &&
publishedAt == other.publishedAt &&
updatedAt == other.updatedAt;
}
@override
int get hashCode {
return $jf($jc(
$jc($jc($jc(0, id.hashCode), title.hashCode), publishedAt.hashCode),
updatedAt.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('CurrentUserCollections')
..add('id', id)
..add('title', title)
..add('publishedAt', publishedAt)
..add('updatedAt', updatedAt))
.toString();
}
}
class CurrentUserCollectionsBuilder
implements Builder<CurrentUserCollections, CurrentUserCollectionsBuilder> {
_$CurrentUserCollections _$v;
int _id;
int get id => _$this._id;
set id(int id) => _$this._id = id;
String _title;
String get title => _$this._title;
set title(String title) => _$this._title = title;
String _publishedAt;
String get publishedAt => _$this._publishedAt;
set publishedAt(String publishedAt) => _$this._publishedAt = publishedAt;
String _updatedAt;
String get updatedAt => _$this._updatedAt;
set updatedAt(String updatedAt) => _$this._updatedAt = updatedAt;
CurrentUserCollectionsBuilder();
CurrentUserCollectionsBuilder get _$this {
if (_$v != null) {
_id = _$v.id;
_title = _$v.title;
_publishedAt = _$v.publishedAt;
_updatedAt = _$v.updatedAt;
_$v = null;
}
return this;
}
@override
void replace(CurrentUserCollections other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$CurrentUserCollections;
}
@override
void update(void Function(CurrentUserCollectionsBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$CurrentUserCollections build() {
final _$result = _$v ??
new _$CurrentUserCollections._(
id: id,
title: title,
publishedAt: publishedAt,
updatedAt: updatedAt);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,53 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'exif.g.dart';
abstract class Exif implements Built<Exif, ExifBuilder> {
factory Exif([void Function(ExifBuilder) updates]) = _$Exif;
Exif._();
@nullable
@BuiltValueField(wireName: 'make')
String get make;
@nullable
@BuiltValueField(wireName: 'model')
String get model;
@nullable
@BuiltValueField(wireName: 'exposure_time')
String get exposureTime;
@nullable
@BuiltValueField(wireName: 'aperture')
String get aperture;
@nullable
@BuiltValueField(wireName: 'focal_length')
String get focalLength;
@nullable
@BuiltValueField(wireName: 'iso')
int get iso;
String toJson() {
return json.encode(serializers.serializeWith(Exif.serializer, this));
}
static Exif fromJson(String jsonString) {
return serializers.deserializeWith(
Exif.serializer, json.decode(jsonString));
}
static Serializer<Exif> get serializer => _$exifSerializer;
}

View File

@@ -0,0 +1,246 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'exif.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Exif> _$exifSerializer = new _$ExifSerializer();
class _$ExifSerializer implements StructuredSerializer<Exif> {
@override
final Iterable<Type> types = const [Exif, _$Exif];
@override
final String wireName = 'Exif';
@override
Iterable<Object> serialize(Serializers serializers, Exif object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[];
if (object.make != null) {
result
..add('make')
..add(serializers.serialize(object.make,
specifiedType: const FullType(String)));
}
if (object.model != null) {
result
..add('model')
..add(serializers.serialize(object.model,
specifiedType: const FullType(String)));
}
if (object.exposureTime != null) {
result
..add('exposure_time')
..add(serializers.serialize(object.exposureTime,
specifiedType: const FullType(String)));
}
if (object.aperture != null) {
result
..add('aperture')
..add(serializers.serialize(object.aperture,
specifiedType: const FullType(String)));
}
if (object.focalLength != null) {
result
..add('focal_length')
..add(serializers.serialize(object.focalLength,
specifiedType: const FullType(String)));
}
if (object.iso != null) {
result
..add('iso')
..add(serializers.serialize(object.iso,
specifiedType: const FullType(int)));
}
return result;
}
@override
Exif deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new ExifBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'make':
result.make = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'model':
result.model = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'exposure_time':
result.exposureTime = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'aperture':
result.aperture = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'focal_length':
result.focalLength = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'iso':
result.iso = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
}
}
return result.build();
}
}
class _$Exif extends Exif {
@override
final String make;
@override
final String model;
@override
final String exposureTime;
@override
final String aperture;
@override
final String focalLength;
@override
final int iso;
factory _$Exif([void Function(ExifBuilder) updates]) =>
(new ExifBuilder()..update(updates)).build();
_$Exif._(
{this.make,
this.model,
this.exposureTime,
this.aperture,
this.focalLength,
this.iso})
: super._();
@override
Exif rebuild(void Function(ExifBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
ExifBuilder toBuilder() => new ExifBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Exif &&
make == other.make &&
model == other.model &&
exposureTime == other.exposureTime &&
aperture == other.aperture &&
focalLength == other.focalLength &&
iso == other.iso;
}
@override
int get hashCode {
return $jf($jc(
$jc(
$jc(
$jc($jc($jc(0, make.hashCode), model.hashCode),
exposureTime.hashCode),
aperture.hashCode),
focalLength.hashCode),
iso.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Exif')
..add('make', make)
..add('model', model)
..add('exposureTime', exposureTime)
..add('aperture', aperture)
..add('focalLength', focalLength)
..add('iso', iso))
.toString();
}
}
class ExifBuilder implements Builder<Exif, ExifBuilder> {
_$Exif _$v;
String _make;
String get make => _$this._make;
set make(String make) => _$this._make = make;
String _model;
String get model => _$this._model;
set model(String model) => _$this._model = model;
String _exposureTime;
String get exposureTime => _$this._exposureTime;
set exposureTime(String exposureTime) => _$this._exposureTime = exposureTime;
String _aperture;
String get aperture => _$this._aperture;
set aperture(String aperture) => _$this._aperture = aperture;
String _focalLength;
String get focalLength => _$this._focalLength;
set focalLength(String focalLength) => _$this._focalLength = focalLength;
int _iso;
int get iso => _$this._iso;
set iso(int iso) => _$this._iso = iso;
ExifBuilder();
ExifBuilder get _$this {
if (_$v != null) {
_make = _$v.make;
_model = _$v.model;
_exposureTime = _$v.exposureTime;
_aperture = _$v.aperture;
_focalLength = _$v.focalLength;
_iso = _$v.iso;
_$v = null;
}
return this;
}
@override
void replace(Exif other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Exif;
}
@override
void update(void Function(ExifBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Exif build() {
final _$result = _$v ??
new _$Exif._(
make: make,
model: model,
exposureTime: exposureTime,
aperture: aperture,
focalLength: focalLength,
iso: iso);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,45 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'links.g.dart';
abstract class Links implements Built<Links, LinksBuilder> {
factory Links([void Function(LinksBuilder) updates]) = _$Links;
Links._();
@nullable
@BuiltValueField(wireName: 'self')
String get self;
@nullable
@BuiltValueField(wireName: 'html')
String get html;
@nullable
@BuiltValueField(wireName: 'download')
String get download;
@nullable
@BuiltValueField(wireName: 'download_location')
String get downloadLocation;
String toJson() {
return json.encode(serializers.serializeWith(Links.serializer, this));
}
static Links fromJson(String jsonString) {
return serializers.deserializeWith(
Links.serializer, json.decode(jsonString));
}
static Serializer<Links> get serializer => _$linksSerializer;
}

View File

@@ -0,0 +1,196 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'links.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Links> _$linksSerializer = new _$LinksSerializer();
class _$LinksSerializer implements StructuredSerializer<Links> {
@override
final Iterable<Type> types = const [Links, _$Links];
@override
final String wireName = 'Links';
@override
Iterable<Object> serialize(Serializers serializers, Links object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[];
if (object.self != null) {
result
..add('self')
..add(serializers.serialize(object.self,
specifiedType: const FullType(String)));
}
if (object.html != null) {
result
..add('html')
..add(serializers.serialize(object.html,
specifiedType: const FullType(String)));
}
if (object.download != null) {
result
..add('download')
..add(serializers.serialize(object.download,
specifiedType: const FullType(String)));
}
if (object.downloadLocation != null) {
result
..add('download_location')
..add(serializers.serialize(object.downloadLocation,
specifiedType: const FullType(String)));
}
return result;
}
@override
Links deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new LinksBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'self':
result.self = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'html':
result.html = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'download':
result.download = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'download_location':
result.downloadLocation = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$Links extends Links {
@override
final String self;
@override
final String html;
@override
final String download;
@override
final String downloadLocation;
factory _$Links([void Function(LinksBuilder) updates]) =>
(new LinksBuilder()..update(updates)).build();
_$Links._({this.self, this.html, this.download, this.downloadLocation})
: super._();
@override
Links rebuild(void Function(LinksBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
LinksBuilder toBuilder() => new LinksBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Links &&
self == other.self &&
html == other.html &&
download == other.download &&
downloadLocation == other.downloadLocation;
}
@override
int get hashCode {
return $jf($jc(
$jc($jc($jc(0, self.hashCode), html.hashCode), download.hashCode),
downloadLocation.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Links')
..add('self', self)
..add('html', html)
..add('download', download)
..add('downloadLocation', downloadLocation))
.toString();
}
}
class LinksBuilder implements Builder<Links, LinksBuilder> {
_$Links _$v;
String _self;
String get self => _$this._self;
set self(String self) => _$this._self = self;
String _html;
String get html => _$this._html;
set html(String html) => _$this._html = html;
String _download;
String get download => _$this._download;
set download(String download) => _$this._download = download;
String _downloadLocation;
String get downloadLocation => _$this._downloadLocation;
set downloadLocation(String downloadLocation) =>
_$this._downloadLocation = downloadLocation;
LinksBuilder();
LinksBuilder get _$this {
if (_$v != null) {
_self = _$v.self;
_html = _$v.html;
_download = _$v.download;
_downloadLocation = _$v.downloadLocation;
_$v = null;
}
return this;
}
@override
void replace(Links other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Links;
}
@override
void update(void Function(LinksBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Links build() {
final _$result = _$v ??
new _$Links._(
self: self,
html: html,
download: download,
downloadLocation: downloadLocation);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,42 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
import 'position.dart';
part 'location.g.dart';
abstract class Location implements Built<Location, LocationBuilder> {
factory Location([void Function(LocationBuilder) updates]) = _$Location;
Location._();
@nullable
@BuiltValueField(wireName: 'city')
String get city;
@nullable
@BuiltValueField(wireName: 'country')
String get country;
@nullable
@BuiltValueField(wireName: 'position')
Position get position;
String toJson() {
return json.encode(serializers.serializeWith(Location.serializer, this));
}
static Location fromJson(String jsonString) {
return serializers.deserializeWith(
Location.serializer, json.decode(jsonString));
}
static Serializer<Location> get serializer => _$locationSerializer;
}

View File

@@ -0,0 +1,184 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'location.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Location> _$locationSerializer = new _$LocationSerializer();
class _$LocationSerializer implements StructuredSerializer<Location> {
@override
final Iterable<Type> types = const [Location, _$Location];
@override
final String wireName = 'Location';
@override
Iterable<Object> serialize(Serializers serializers, Location object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[];
if (object.city != null) {
result
..add('city')
..add(serializers.serialize(object.city,
specifiedType: const FullType(String)));
}
if (object.country != null) {
result
..add('country')
..add(serializers.serialize(object.country,
specifiedType: const FullType(String)));
}
if (object.position != null) {
result
..add('position')
..add(serializers.serialize(object.position,
specifiedType: const FullType(Position)));
}
return result;
}
@override
Location deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new LocationBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'city':
result.city = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'country':
result.country = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'position':
result.position.replace(serializers.deserialize(value,
specifiedType: const FullType(Position)) as Position);
break;
}
}
return result.build();
}
}
class _$Location extends Location {
@override
final String city;
@override
final String country;
@override
final Position position;
factory _$Location([void Function(LocationBuilder) updates]) =>
(new LocationBuilder()..update(updates)).build();
_$Location._({this.city, this.country, this.position}) : super._();
@override
Location rebuild(void Function(LocationBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
LocationBuilder toBuilder() => new LocationBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Location &&
city == other.city &&
country == other.country &&
position == other.position;
}
@override
int get hashCode {
return $jf(
$jc($jc($jc(0, city.hashCode), country.hashCode), position.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Location')
..add('city', city)
..add('country', country)
..add('position', position))
.toString();
}
}
class LocationBuilder implements Builder<Location, LocationBuilder> {
_$Location _$v;
String _city;
String get city => _$this._city;
set city(String city) => _$this._city = city;
String _country;
String get country => _$this._country;
set country(String country) => _$this._country = country;
PositionBuilder _position;
PositionBuilder get position => _$this._position ??= new PositionBuilder();
set position(PositionBuilder position) => _$this._position = position;
LocationBuilder();
LocationBuilder get _$this {
if (_$v != null) {
_city = _$v.city;
_country = _$v.country;
_position = _$v.position?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(Location other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Location;
}
@override
void update(void Function(LocationBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Location build() {
_$Location _$result;
try {
_$result = _$v ??
new _$Location._(
city: city, country: country, position: _position?.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'position';
_position?.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'Location', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,104 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
import 'current_user_collections.dart';
import 'exif.dart';
import 'links.dart';
import 'location.dart';
import 'tags.dart';
import 'urls.dart';
import 'user.dart';
part 'photo.g.dart';
abstract class Photo implements Built<Photo, PhotoBuilder> {
factory Photo([void Function(PhotoBuilder) updates]) = _$Photo;
Photo._();
@BuiltValueField(wireName: 'id')
String get id;
@nullable
@BuiltValueField(wireName: 'created_at')
String get createdAt;
@nullable
@BuiltValueField(wireName: 'updated_at')
String get updatedAt;
@nullable
@BuiltValueField(wireName: 'width')
int get width;
@nullable
@BuiltValueField(wireName: 'height')
int get height;
@nullable
@BuiltValueField(wireName: 'color')
String get color;
@nullable
@BuiltValueField(wireName: 'downloads')
int get downloads;
@nullable
@BuiltValueField(wireName: 'likes')
int get likes;
@nullable
@BuiltValueField(wireName: 'liked_by_user')
bool get likedByUser;
@nullable
@BuiltValueField(wireName: 'description')
String get description;
@nullable
@BuiltValueField(wireName: 'exif')
Exif get exif;
@nullable
@BuiltValueField(wireName: 'location')
Location get location;
@nullable
@BuiltValueField(wireName: 'tags')
BuiltList<Tags> get tags;
@nullable
@BuiltValueField(wireName: 'current_user_collections')
BuiltList<CurrentUserCollections> get currentUserCollections;
@nullable
@BuiltValueField(wireName: 'urls')
Urls get urls;
@nullable
@BuiltValueField(wireName: 'links')
Links get links;
@nullable
@BuiltValueField(wireName: 'user')
User get user;
String toJson() {
return json.encode(serializers.serializeWith(Photo.serializer, this));
}
static Photo fromJson(String jsonString) {
return serializers.deserializeWith(
Photo.serializer, json.decode(jsonString));
}
static Serializer<Photo> get serializer => _$photoSerializer;
}

View File

@@ -0,0 +1,543 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'photo.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Photo> _$photoSerializer = new _$PhotoSerializer();
class _$PhotoSerializer implements StructuredSerializer<Photo> {
@override
final Iterable<Type> types = const [Photo, _$Photo];
@override
final String wireName = 'Photo';
@override
Iterable<Object> serialize(Serializers serializers, Photo object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'id',
serializers.serialize(object.id, specifiedType: const FullType(String)),
];
if (object.createdAt != null) {
result
..add('created_at')
..add(serializers.serialize(object.createdAt,
specifiedType: const FullType(String)));
}
if (object.updatedAt != null) {
result
..add('updated_at')
..add(serializers.serialize(object.updatedAt,
specifiedType: const FullType(String)));
}
if (object.width != null) {
result
..add('width')
..add(serializers.serialize(object.width,
specifiedType: const FullType(int)));
}
if (object.height != null) {
result
..add('height')
..add(serializers.serialize(object.height,
specifiedType: const FullType(int)));
}
if (object.color != null) {
result
..add('color')
..add(serializers.serialize(object.color,
specifiedType: const FullType(String)));
}
if (object.downloads != null) {
result
..add('downloads')
..add(serializers.serialize(object.downloads,
specifiedType: const FullType(int)));
}
if (object.likes != null) {
result
..add('likes')
..add(serializers.serialize(object.likes,
specifiedType: const FullType(int)));
}
if (object.likedByUser != null) {
result
..add('liked_by_user')
..add(serializers.serialize(object.likedByUser,
specifiedType: const FullType(bool)));
}
if (object.description != null) {
result
..add('description')
..add(serializers.serialize(object.description,
specifiedType: const FullType(String)));
}
if (object.exif != null) {
result
..add('exif')
..add(serializers.serialize(object.exif,
specifiedType: const FullType(Exif)));
}
if (object.location != null) {
result
..add('location')
..add(serializers.serialize(object.location,
specifiedType: const FullType(Location)));
}
if (object.tags != null) {
result
..add('tags')
..add(serializers.serialize(object.tags,
specifiedType:
const FullType(BuiltList, const [const FullType(Tags)])));
}
if (object.currentUserCollections != null) {
result
..add('current_user_collections')
..add(serializers.serialize(object.currentUserCollections,
specifiedType: const FullType(
BuiltList, const [const FullType(CurrentUserCollections)])));
}
if (object.urls != null) {
result
..add('urls')
..add(serializers.serialize(object.urls,
specifiedType: const FullType(Urls)));
}
if (object.links != null) {
result
..add('links')
..add(serializers.serialize(object.links,
specifiedType: const FullType(Links)));
}
if (object.user != null) {
result
..add('user')
..add(serializers.serialize(object.user,
specifiedType: const FullType(User)));
}
return result;
}
@override
Photo deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new PhotoBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'id':
result.id = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'created_at':
result.createdAt = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'updated_at':
result.updatedAt = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'width':
result.width = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'height':
result.height = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'color':
result.color = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'downloads':
result.downloads = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'likes':
result.likes = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'liked_by_user':
result.likedByUser = serializers.deserialize(value,
specifiedType: const FullType(bool)) as bool;
break;
case 'description':
result.description = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'exif':
result.exif.replace(serializers.deserialize(value,
specifiedType: const FullType(Exif)) as Exif);
break;
case 'location':
result.location.replace(serializers.deserialize(value,
specifiedType: const FullType(Location)) as Location);
break;
case 'tags':
result.tags.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(Tags)]))
as BuiltList<dynamic>);
break;
case 'current_user_collections':
result.currentUserCollections.replace(serializers.deserialize(value,
specifiedType: const FullType(BuiltList, const [
const FullType(CurrentUserCollections)
])) as BuiltList<dynamic>);
break;
case 'urls':
result.urls.replace(serializers.deserialize(value,
specifiedType: const FullType(Urls)) as Urls);
break;
case 'links':
result.links.replace(serializers.deserialize(value,
specifiedType: const FullType(Links)) as Links);
break;
case 'user':
result.user.replace(serializers.deserialize(value,
specifiedType: const FullType(User)) as User);
break;
}
}
return result.build();
}
}
class _$Photo extends Photo {
@override
final String id;
@override
final String createdAt;
@override
final String updatedAt;
@override
final int width;
@override
final int height;
@override
final String color;
@override
final int downloads;
@override
final int likes;
@override
final bool likedByUser;
@override
final String description;
@override
final Exif exif;
@override
final Location location;
@override
final BuiltList<Tags> tags;
@override
final BuiltList<CurrentUserCollections> currentUserCollections;
@override
final Urls urls;
@override
final Links links;
@override
final User user;
factory _$Photo([void Function(PhotoBuilder) updates]) =>
(new PhotoBuilder()..update(updates)).build();
_$Photo._(
{this.id,
this.createdAt,
this.updatedAt,
this.width,
this.height,
this.color,
this.downloads,
this.likes,
this.likedByUser,
this.description,
this.exif,
this.location,
this.tags,
this.currentUserCollections,
this.urls,
this.links,
this.user})
: super._() {
if (id == null) {
throw new BuiltValueNullFieldError('Photo', 'id');
}
}
@override
Photo rebuild(void Function(PhotoBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
PhotoBuilder toBuilder() => new PhotoBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Photo &&
id == other.id &&
createdAt == other.createdAt &&
updatedAt == other.updatedAt &&
width == other.width &&
height == other.height &&
color == other.color &&
downloads == other.downloads &&
likes == other.likes &&
likedByUser == other.likedByUser &&
description == other.description &&
exif == other.exif &&
location == other.location &&
tags == other.tags &&
currentUserCollections == other.currentUserCollections &&
urls == other.urls &&
links == other.links &&
user == other.user;
}
@override
int get hashCode {
return $jf($jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
0,
id
.hashCode),
createdAt
.hashCode),
updatedAt
.hashCode),
width.hashCode),
height.hashCode),
color.hashCode),
downloads.hashCode),
likes.hashCode),
likedByUser.hashCode),
description.hashCode),
exif.hashCode),
location.hashCode),
tags.hashCode),
currentUserCollections.hashCode),
urls.hashCode),
links.hashCode),
user.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Photo')
..add('id', id)
..add('createdAt', createdAt)
..add('updatedAt', updatedAt)
..add('width', width)
..add('height', height)
..add('color', color)
..add('downloads', downloads)
..add('likes', likes)
..add('likedByUser', likedByUser)
..add('description', description)
..add('exif', exif)
..add('location', location)
..add('tags', tags)
..add('currentUserCollections', currentUserCollections)
..add('urls', urls)
..add('links', links)
..add('user', user))
.toString();
}
}
class PhotoBuilder implements Builder<Photo, PhotoBuilder> {
_$Photo _$v;
String _id;
String get id => _$this._id;
set id(String id) => _$this._id = id;
String _createdAt;
String get createdAt => _$this._createdAt;
set createdAt(String createdAt) => _$this._createdAt = createdAt;
String _updatedAt;
String get updatedAt => _$this._updatedAt;
set updatedAt(String updatedAt) => _$this._updatedAt = updatedAt;
int _width;
int get width => _$this._width;
set width(int width) => _$this._width = width;
int _height;
int get height => _$this._height;
set height(int height) => _$this._height = height;
String _color;
String get color => _$this._color;
set color(String color) => _$this._color = color;
int _downloads;
int get downloads => _$this._downloads;
set downloads(int downloads) => _$this._downloads = downloads;
int _likes;
int get likes => _$this._likes;
set likes(int likes) => _$this._likes = likes;
bool _likedByUser;
bool get likedByUser => _$this._likedByUser;
set likedByUser(bool likedByUser) => _$this._likedByUser = likedByUser;
String _description;
String get description => _$this._description;
set description(String description) => _$this._description = description;
ExifBuilder _exif;
ExifBuilder get exif => _$this._exif ??= new ExifBuilder();
set exif(ExifBuilder exif) => _$this._exif = exif;
LocationBuilder _location;
LocationBuilder get location => _$this._location ??= new LocationBuilder();
set location(LocationBuilder location) => _$this._location = location;
ListBuilder<Tags> _tags;
ListBuilder<Tags> get tags => _$this._tags ??= new ListBuilder<Tags>();
set tags(ListBuilder<Tags> tags) => _$this._tags = tags;
ListBuilder<CurrentUserCollections> _currentUserCollections;
ListBuilder<CurrentUserCollections> get currentUserCollections =>
_$this._currentUserCollections ??=
new ListBuilder<CurrentUserCollections>();
set currentUserCollections(
ListBuilder<CurrentUserCollections> currentUserCollections) =>
_$this._currentUserCollections = currentUserCollections;
UrlsBuilder _urls;
UrlsBuilder get urls => _$this._urls ??= new UrlsBuilder();
set urls(UrlsBuilder urls) => _$this._urls = urls;
LinksBuilder _links;
LinksBuilder get links => _$this._links ??= new LinksBuilder();
set links(LinksBuilder links) => _$this._links = links;
UserBuilder _user;
UserBuilder get user => _$this._user ??= new UserBuilder();
set user(UserBuilder user) => _$this._user = user;
PhotoBuilder();
PhotoBuilder get _$this {
if (_$v != null) {
_id = _$v.id;
_createdAt = _$v.createdAt;
_updatedAt = _$v.updatedAt;
_width = _$v.width;
_height = _$v.height;
_color = _$v.color;
_downloads = _$v.downloads;
_likes = _$v.likes;
_likedByUser = _$v.likedByUser;
_description = _$v.description;
_exif = _$v.exif?.toBuilder();
_location = _$v.location?.toBuilder();
_tags = _$v.tags?.toBuilder();
_currentUserCollections = _$v.currentUserCollections?.toBuilder();
_urls = _$v.urls?.toBuilder();
_links = _$v.links?.toBuilder();
_user = _$v.user?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(Photo other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Photo;
}
@override
void update(void Function(PhotoBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Photo build() {
_$Photo _$result;
try {
_$result = _$v ??
new _$Photo._(
id: id,
createdAt: createdAt,
updatedAt: updatedAt,
width: width,
height: height,
color: color,
downloads: downloads,
likes: likes,
likedByUser: likedByUser,
description: description,
exif: _exif?.build(),
location: _location?.build(),
tags: _tags?.build(),
currentUserCollections: _currentUserCollections?.build(),
urls: _urls?.build(),
links: _links?.build(),
user: _user?.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'exif';
_exif?.build();
_$failedField = 'location';
_location?.build();
_$failedField = 'tags';
_tags?.build();
_$failedField = 'currentUserCollections';
_currentUserCollections?.build();
_$failedField = 'urls';
_urls?.build();
_$failedField = 'links';
_links?.build();
_$failedField = 'user';
_user?.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'Photo', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,35 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'position.g.dart';
abstract class Position implements Built<Position, PositionBuilder> {
factory Position([void Function(PositionBuilder) updates]) = _$Position;
Position._();
@BuiltValueField(wireName: 'latitude')
double get latitude;
@BuiltValueField(wireName: 'longitude')
double get longitude;
String toJson() {
return json.encode(serializers.serializeWith(Position.serializer, this));
}
static Position fromJson(String jsonString) {
return serializers.deserializeWith(
Position.serializer, json.decode(jsonString));
}
static Serializer<Position> get serializer => _$positionSerializer;
}

View File

@@ -0,0 +1,153 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'position.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Position> _$positionSerializer = new _$PositionSerializer();
class _$PositionSerializer implements StructuredSerializer<Position> {
@override
final Iterable<Type> types = const [Position, _$Position];
@override
final String wireName = 'Position';
@override
Iterable<Object> serialize(Serializers serializers, Position object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'latitude',
serializers.serialize(object.latitude,
specifiedType: const FullType(double)),
'longitude',
serializers.serialize(object.longitude,
specifiedType: const FullType(double)),
];
return result;
}
@override
Position deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new PositionBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'latitude':
result.latitude = serializers.deserialize(value,
specifiedType: const FullType(double)) as double;
break;
case 'longitude':
result.longitude = serializers.deserialize(value,
specifiedType: const FullType(double)) as double;
break;
}
}
return result.build();
}
}
class _$Position extends Position {
@override
final double latitude;
@override
final double longitude;
factory _$Position([void Function(PositionBuilder) updates]) =>
(new PositionBuilder()..update(updates)).build();
_$Position._({this.latitude, this.longitude}) : super._() {
if (latitude == null) {
throw new BuiltValueNullFieldError('Position', 'latitude');
}
if (longitude == null) {
throw new BuiltValueNullFieldError('Position', 'longitude');
}
}
@override
Position rebuild(void Function(PositionBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
PositionBuilder toBuilder() => new PositionBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Position &&
latitude == other.latitude &&
longitude == other.longitude;
}
@override
int get hashCode {
return $jf($jc($jc(0, latitude.hashCode), longitude.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Position')
..add('latitude', latitude)
..add('longitude', longitude))
.toString();
}
}
class PositionBuilder implements Builder<Position, PositionBuilder> {
_$Position _$v;
double _latitude;
double get latitude => _$this._latitude;
set latitude(double latitude) => _$this._latitude = latitude;
double _longitude;
double get longitude => _$this._longitude;
set longitude(double longitude) => _$this._longitude = longitude;
PositionBuilder();
PositionBuilder get _$this {
if (_$v != null) {
_latitude = _$v.latitude;
_longitude = _$v.longitude;
_$v = null;
}
return this;
}
@override
void replace(Position other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Position;
}
@override
void update(void Function(PositionBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Position build() {
final _$result =
_$v ?? new _$Position._(latitude: latitude, longitude: longitude);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,47 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
import 'photo.dart';
part 'search_photos_response.g.dart';
abstract class SearchPhotosResponse
implements Built<SearchPhotosResponse, SearchPhotosResponseBuilder> {
factory SearchPhotosResponse(
[void Function(SearchPhotosResponseBuilder) updates]) =
_$SearchPhotosResponse;
SearchPhotosResponse._();
@nullable
@BuiltValueField(wireName: 'total')
int get total;
@nullable
@BuiltValueField(wireName: 'total_pages')
int get totalPages;
@BuiltValueField(wireName: 'results')
BuiltList<Photo> get results;
String toJson() {
return json.encode(
serializers.serializeWith(SearchPhotosResponse.serializer, this));
}
static SearchPhotosResponse fromJson(String jsonString) {
return serializers.deserializeWith(
SearchPhotosResponse.serializer, json.decode(jsonString));
}
static Serializer<SearchPhotosResponse> get serializer =>
_$searchPhotosResponseSerializer;
}

View File

@@ -0,0 +1,202 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'search_photos_response.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<SearchPhotosResponse> _$searchPhotosResponseSerializer =
new _$SearchPhotosResponseSerializer();
class _$SearchPhotosResponseSerializer
implements StructuredSerializer<SearchPhotosResponse> {
@override
final Iterable<Type> types = const [
SearchPhotosResponse,
_$SearchPhotosResponse
];
@override
final String wireName = 'SearchPhotosResponse';
@override
Iterable<Object> serialize(
Serializers serializers, SearchPhotosResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'results',
serializers.serialize(object.results,
specifiedType:
const FullType(BuiltList, const [const FullType(Photo)])),
];
if (object.total != null) {
result
..add('total')
..add(serializers.serialize(object.total,
specifiedType: const FullType(int)));
}
if (object.totalPages != null) {
result
..add('total_pages')
..add(serializers.serialize(object.totalPages,
specifiedType: const FullType(int)));
}
return result;
}
@override
SearchPhotosResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new SearchPhotosResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'total':
result.total = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'total_pages':
result.totalPages = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'results':
result.results.replace(serializers.deserialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(Photo)]))
as BuiltList<dynamic>);
break;
}
}
return result.build();
}
}
class _$SearchPhotosResponse extends SearchPhotosResponse {
@override
final int total;
@override
final int totalPages;
@override
final BuiltList<Photo> results;
factory _$SearchPhotosResponse(
[void Function(SearchPhotosResponseBuilder) updates]) =>
(new SearchPhotosResponseBuilder()..update(updates)).build();
_$SearchPhotosResponse._({this.total, this.totalPages, this.results})
: super._() {
if (results == null) {
throw new BuiltValueNullFieldError('SearchPhotosResponse', 'results');
}
}
@override
SearchPhotosResponse rebuild(
void Function(SearchPhotosResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
SearchPhotosResponseBuilder toBuilder() =>
new SearchPhotosResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is SearchPhotosResponse &&
total == other.total &&
totalPages == other.totalPages &&
results == other.results;
}
@override
int get hashCode {
return $jf($jc(
$jc($jc(0, total.hashCode), totalPages.hashCode), results.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('SearchPhotosResponse')
..add('total', total)
..add('totalPages', totalPages)
..add('results', results))
.toString();
}
}
class SearchPhotosResponseBuilder
implements Builder<SearchPhotosResponse, SearchPhotosResponseBuilder> {
_$SearchPhotosResponse _$v;
int _total;
int get total => _$this._total;
set total(int total) => _$this._total = total;
int _totalPages;
int get totalPages => _$this._totalPages;
set totalPages(int totalPages) => _$this._totalPages = totalPages;
ListBuilder<Photo> _results;
ListBuilder<Photo> get results =>
_$this._results ??= new ListBuilder<Photo>();
set results(ListBuilder<Photo> results) => _$this._results = results;
SearchPhotosResponseBuilder();
SearchPhotosResponseBuilder get _$this {
if (_$v != null) {
_total = _$v.total;
_totalPages = _$v.totalPages;
_results = _$v.results?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(SearchPhotosResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$SearchPhotosResponse;
}
@override
void update(void Function(SearchPhotosResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$SearchPhotosResponse build() {
_$SearchPhotosResponse _$result;
try {
_$result = _$v ??
new _$SearchPhotosResponse._(
total: total, totalPages: totalPages, results: results.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'results';
results.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'SearchPhotosResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,32 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'tags.g.dart';
abstract class Tags implements Built<Tags, TagsBuilder> {
factory Tags([void Function(TagsBuilder) updates]) = _$Tags;
Tags._();
@BuiltValueField(wireName: 'title')
String get title;
String toJson() {
return json.encode(serializers.serializeWith(Tags.serializer, this));
}
static Tags fromJson(String jsonString) {
return serializers.deserializeWith(
Tags.serializer, json.decode(jsonString));
}
static Serializer<Tags> get serializer => _$tagsSerializer;
}

View File

@@ -0,0 +1,131 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tags.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Tags> _$tagsSerializer = new _$TagsSerializer();
class _$TagsSerializer implements StructuredSerializer<Tags> {
@override
final Iterable<Type> types = const [Tags, _$Tags];
@override
final String wireName = 'Tags';
@override
Iterable<Object> serialize(Serializers serializers, Tags object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'title',
serializers.serialize(object.title,
specifiedType: const FullType(String)),
];
return result;
}
@override
Tags deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TagsBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'title':
result.title = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$Tags extends Tags {
@override
final String title;
factory _$Tags([void Function(TagsBuilder) updates]) =>
(new TagsBuilder()..update(updates)).build();
_$Tags._({this.title}) : super._() {
if (title == null) {
throw new BuiltValueNullFieldError('Tags', 'title');
}
}
@override
Tags rebuild(void Function(TagsBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
TagsBuilder toBuilder() => new TagsBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Tags && title == other.title;
}
@override
int get hashCode {
return $jf($jc(0, title.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Tags')..add('title', title))
.toString();
}
}
class TagsBuilder implements Builder<Tags, TagsBuilder> {
_$Tags _$v;
String _title;
String get title => _$this._title;
set title(String title) => _$this._title = title;
TagsBuilder();
TagsBuilder get _$this {
if (_$v != null) {
_title = _$v.title;
_$v = null;
}
return this;
}
@override
void replace(Tags other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Tags;
}
@override
void update(void Function(TagsBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Tags build() {
final _$result = _$v ?? new _$Tags._(title: title);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,122 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:meta/meta.dart';
import 'package:pedantic/pedantic.dart';
import 'api_error.dart';
import 'photo.dart';
import 'search_photos_response.dart';
final _unsplashBaseUrl = Uri.parse('https://api.unsplash.com/');
/// Unsplash API Client. Requires an
/// [Unsplash API](https://unsplash.com/developers) `accessKey` to make
/// requests to the Unsplash API.
class Unsplash {
Unsplash({
@required String accessKey,
http.BaseClient httpClient,
}) : assert(accessKey != null, 'accessKey must not be null'),
_accessKey = accessKey,
_client = httpClient ?? http.Client();
final String _accessKey;
final http.Client _client;
final _log = Logger('Unsplash');
Future<SearchPhotosResponse> searchPhotos({
@required String query,
num page = 1,
num perPage = 10,
List<num> collections = const [],
SearchPhotosOrientation orientation,
}) async {
final searchPhotosUrl = _unsplashBaseUrl
.replace(path: '/search/photos', queryParameters: <String, String>{
'query': query,
if (page != 1) 'page': '$page',
if (perPage != 10) 'per_page': '$perPage',
if (collections != null && collections.isNotEmpty)
'collections': '${collections.join(',')}',
if (orientation == SearchPhotosOrientation.landscape)
'orientation': 'landscape',
if (orientation == SearchPhotosOrientation.portrait)
'orientation': 'portrait',
if (orientation == SearchPhotosOrientation.squarish)
'orientation': 'squarish',
});
_log.info('GET $searchPhotosUrl');
final response = await _client.get(
searchPhotosUrl,
headers: {
'Accept-Version': 'v1',
'Authorization': 'Client-ID $_accessKey',
},
);
dynamic body;
try {
body = json.decode(response.body);
} catch (e) {
throw UnsplashException('Invalid JSON received');
}
if (body is Map &&
body['errors'] is List &&
body['errors'].isNotEmpty as bool) {
final apiError = ApiError.fromJson(response.body);
throw UnsplashException(apiError.errors.join(', '));
}
return SearchPhotosResponse.fromJson(
response.body,
);
}
Future<Uint8List> download(Photo photo) async {
// For detail on how downloading photos from Unsplash, please see
// https://help.unsplash.com/en/articles/2511258-guideline-triggering-a-download
_log.info('GET ${photo.urls.full}');
final futureBytes = http.readBytes(photo.urls.full, headers: {
'Accept-Version': 'v1',
'Authorization': 'Client-ID $_accessKey',
});
_log.info('GET ${photo.links.downloadLocation}');
unawaited(http.get(photo.links.downloadLocation, headers: {
'Accept-Version': 'v1',
'Authorization': 'Client-ID $_accessKey',
}));
return futureBytes;
}
}
enum SearchPhotosOrientation {
landscape,
portrait,
squarish,
}
class UnsplashException implements Exception {
UnsplashException([this.message]);
final String message;
@override
String toString() {
if (message == null) {
return 'UnsplashException';
}
return 'UnsplashException: $message';
}
}

View File

@@ -0,0 +1,49 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
part 'urls.g.dart';
abstract class Urls implements Built<Urls, UrlsBuilder> {
factory Urls([void Function(UrlsBuilder b) updates]) = _$Urls;
Urls._();
@nullable
@BuiltValueField(wireName: 'raw')
String get raw;
@nullable
@BuiltValueField(wireName: 'full')
String get full;
@nullable
@BuiltValueField(wireName: 'regular')
String get regular;
@nullable
@BuiltValueField(wireName: 'small')
String get small;
@nullable
@BuiltValueField(wireName: 'thumb')
String get thumb;
String toJson() {
return json.encode(serializers.serializeWith(Urls.serializer, this));
}
static Urls fromJson(String jsonString) {
return serializers.deserializeWith(
Urls.serializer, json.decode(jsonString));
}
static Serializer<Urls> get serializer => _$urlsSerializer;
}

View File

@@ -0,0 +1,212 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'urls.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Urls> _$urlsSerializer = new _$UrlsSerializer();
class _$UrlsSerializer implements StructuredSerializer<Urls> {
@override
final Iterable<Type> types = const [Urls, _$Urls];
@override
final String wireName = 'Urls';
@override
Iterable<Object> serialize(Serializers serializers, Urls object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[];
if (object.raw != null) {
result
..add('raw')
..add(serializers.serialize(object.raw,
specifiedType: const FullType(String)));
}
if (object.full != null) {
result
..add('full')
..add(serializers.serialize(object.full,
specifiedType: const FullType(String)));
}
if (object.regular != null) {
result
..add('regular')
..add(serializers.serialize(object.regular,
specifiedType: const FullType(String)));
}
if (object.small != null) {
result
..add('small')
..add(serializers.serialize(object.small,
specifiedType: const FullType(String)));
}
if (object.thumb != null) {
result
..add('thumb')
..add(serializers.serialize(object.thumb,
specifiedType: const FullType(String)));
}
return result;
}
@override
Urls deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new UrlsBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'raw':
result.raw = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'full':
result.full = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'regular':
result.regular = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'small':
result.small = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'thumb':
result.thumb = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$Urls extends Urls {
@override
final String raw;
@override
final String full;
@override
final String regular;
@override
final String small;
@override
final String thumb;
factory _$Urls([void Function(UrlsBuilder) updates]) =>
(new UrlsBuilder()..update(updates)).build();
_$Urls._({this.raw, this.full, this.regular, this.small, this.thumb})
: super._();
@override
Urls rebuild(void Function(UrlsBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
UrlsBuilder toBuilder() => new UrlsBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is Urls &&
raw == other.raw &&
full == other.full &&
regular == other.regular &&
small == other.small &&
thumb == other.thumb;
}
@override
int get hashCode {
return $jf($jc(
$jc($jc($jc($jc(0, raw.hashCode), full.hashCode), regular.hashCode),
small.hashCode),
thumb.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('Urls')
..add('raw', raw)
..add('full', full)
..add('regular', regular)
..add('small', small)
..add('thumb', thumb))
.toString();
}
}
class UrlsBuilder implements Builder<Urls, UrlsBuilder> {
_$Urls _$v;
String _raw;
String get raw => _$this._raw;
set raw(String raw) => _$this._raw = raw;
String _full;
String get full => _$this._full;
set full(String full) => _$this._full = full;
String _regular;
String get regular => _$this._regular;
set regular(String regular) => _$this._regular = regular;
String _small;
String get small => _$this._small;
set small(String small) => _$this._small = small;
String _thumb;
String get thumb => _$this._thumb;
set thumb(String thumb) => _$this._thumb = thumb;
UrlsBuilder();
UrlsBuilder get _$this {
if (_$v != null) {
_raw = _$v.raw;
_full = _$v.full;
_regular = _$v.regular;
_small = _$v.small;
_thumb = _$v.thumb;
_$v = null;
}
return this;
}
@override
void replace(Urls other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$Urls;
}
@override
void update(void Function(UrlsBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$Urls build() {
final _$result = _$v ??
new _$Urls._(
raw: raw, full: full, regular: regular, small: small, thumb: thumb);
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,71 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import '../serializers.dart';
import 'links.dart';
part 'user.g.dart';
abstract class User implements Built<User, UserBuilder> {
factory User([void Function(UserBuilder) updates]) = _$User;
User._();
@BuiltValueField(wireName: 'id')
String get id;
@nullable
@BuiltValueField(wireName: 'updated_at')
String get updatedAt;
@BuiltValueField(wireName: 'username')
String get username;
@BuiltValueField(wireName: 'name')
String get name;
@nullable
@BuiltValueField(wireName: 'portfolio_url')
String get portfolioUrl;
@nullable
@BuiltValueField(wireName: 'bio')
String get bio;
@nullable
@BuiltValueField(wireName: 'location')
String get location;
@nullable
@BuiltValueField(wireName: 'total_likes')
int get totalLikes;
@nullable
@BuiltValueField(wireName: 'total_photos')
int get totalPhotos;
@nullable
@BuiltValueField(wireName: 'total_collections')
int get totalCollections;
@nullable
@BuiltValueField(wireName: 'links')
Links get links;
String toJson() {
return json.encode(serializers.serializeWith(User.serializer, this));
}
static User fromJson(String jsonString) {
return serializers.deserializeWith(
User.serializer, json.decode(jsonString));
}
static Serializer<User> get serializer => _$userSerializer;
}

View File

@@ -0,0 +1,377 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<User> _$userSerializer = new _$UserSerializer();
class _$UserSerializer implements StructuredSerializer<User> {
@override
final Iterable<Type> types = const [User, _$User];
@override
final String wireName = 'User';
@override
Iterable<Object> serialize(Serializers serializers, User object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'id',
serializers.serialize(object.id, specifiedType: const FullType(String)),
'username',
serializers.serialize(object.username,
specifiedType: const FullType(String)),
'name',
serializers.serialize(object.name, specifiedType: const FullType(String)),
];
if (object.updatedAt != null) {
result
..add('updated_at')
..add(serializers.serialize(object.updatedAt,
specifiedType: const FullType(String)));
}
if (object.portfolioUrl != null) {
result
..add('portfolio_url')
..add(serializers.serialize(object.portfolioUrl,
specifiedType: const FullType(String)));
}
if (object.bio != null) {
result
..add('bio')
..add(serializers.serialize(object.bio,
specifiedType: const FullType(String)));
}
if (object.location != null) {
result
..add('location')
..add(serializers.serialize(object.location,
specifiedType: const FullType(String)));
}
if (object.totalLikes != null) {
result
..add('total_likes')
..add(serializers.serialize(object.totalLikes,
specifiedType: const FullType(int)));
}
if (object.totalPhotos != null) {
result
..add('total_photos')
..add(serializers.serialize(object.totalPhotos,
specifiedType: const FullType(int)));
}
if (object.totalCollections != null) {
result
..add('total_collections')
..add(serializers.serialize(object.totalCollections,
specifiedType: const FullType(int)));
}
if (object.links != null) {
result
..add('links')
..add(serializers.serialize(object.links,
specifiedType: const FullType(Links)));
}
return result;
}
@override
User deserialize(Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new UserBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'id':
result.id = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'updated_at':
result.updatedAt = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'username':
result.username = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'name':
result.name = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'portfolio_url':
result.portfolioUrl = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'bio':
result.bio = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'location':
result.location = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
case 'total_likes':
result.totalLikes = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'total_photos':
result.totalPhotos = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'total_collections':
result.totalCollections = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'links':
result.links.replace(serializers.deserialize(value,
specifiedType: const FullType(Links)) as Links);
break;
}
}
return result.build();
}
}
class _$User extends User {
@override
final String id;
@override
final String updatedAt;
@override
final String username;
@override
final String name;
@override
final String portfolioUrl;
@override
final String bio;
@override
final String location;
@override
final int totalLikes;
@override
final int totalPhotos;
@override
final int totalCollections;
@override
final Links links;
factory _$User([void Function(UserBuilder) updates]) =>
(new UserBuilder()..update(updates)).build();
_$User._(
{this.id,
this.updatedAt,
this.username,
this.name,
this.portfolioUrl,
this.bio,
this.location,
this.totalLikes,
this.totalPhotos,
this.totalCollections,
this.links})
: super._() {
if (id == null) {
throw new BuiltValueNullFieldError('User', 'id');
}
if (username == null) {
throw new BuiltValueNullFieldError('User', 'username');
}
if (name == null) {
throw new BuiltValueNullFieldError('User', 'name');
}
}
@override
User rebuild(void Function(UserBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
UserBuilder toBuilder() => new UserBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is User &&
id == other.id &&
updatedAt == other.updatedAt &&
username == other.username &&
name == other.name &&
portfolioUrl == other.portfolioUrl &&
bio == other.bio &&
location == other.location &&
totalLikes == other.totalLikes &&
totalPhotos == other.totalPhotos &&
totalCollections == other.totalCollections &&
links == other.links;
}
@override
int get hashCode {
return $jf($jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc(
$jc($jc(0, id.hashCode),
updatedAt.hashCode),
username.hashCode),
name.hashCode),
portfolioUrl.hashCode),
bio.hashCode),
location.hashCode),
totalLikes.hashCode),
totalPhotos.hashCode),
totalCollections.hashCode),
links.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('User')
..add('id', id)
..add('updatedAt', updatedAt)
..add('username', username)
..add('name', name)
..add('portfolioUrl', portfolioUrl)
..add('bio', bio)
..add('location', location)
..add('totalLikes', totalLikes)
..add('totalPhotos', totalPhotos)
..add('totalCollections', totalCollections)
..add('links', links))
.toString();
}
}
class UserBuilder implements Builder<User, UserBuilder> {
_$User _$v;
String _id;
String get id => _$this._id;
set id(String id) => _$this._id = id;
String _updatedAt;
String get updatedAt => _$this._updatedAt;
set updatedAt(String updatedAt) => _$this._updatedAt = updatedAt;
String _username;
String get username => _$this._username;
set username(String username) => _$this._username = username;
String _name;
String get name => _$this._name;
set name(String name) => _$this._name = name;
String _portfolioUrl;
String get portfolioUrl => _$this._portfolioUrl;
set portfolioUrl(String portfolioUrl) => _$this._portfolioUrl = portfolioUrl;
String _bio;
String get bio => _$this._bio;
set bio(String bio) => _$this._bio = bio;
String _location;
String get location => _$this._location;
set location(String location) => _$this._location = location;
int _totalLikes;
int get totalLikes => _$this._totalLikes;
set totalLikes(int totalLikes) => _$this._totalLikes = totalLikes;
int _totalPhotos;
int get totalPhotos => _$this._totalPhotos;
set totalPhotos(int totalPhotos) => _$this._totalPhotos = totalPhotos;
int _totalCollections;
int get totalCollections => _$this._totalCollections;
set totalCollections(int totalCollections) =>
_$this._totalCollections = totalCollections;
LinksBuilder _links;
LinksBuilder get links => _$this._links ??= new LinksBuilder();
set links(LinksBuilder links) => _$this._links = links;
UserBuilder();
UserBuilder get _$this {
if (_$v != null) {
_id = _$v.id;
_updatedAt = _$v.updatedAt;
_username = _$v.username;
_name = _$v.name;
_portfolioUrl = _$v.portfolioUrl;
_bio = _$v.bio;
_location = _$v.location;
_totalLikes = _$v.totalLikes;
_totalPhotos = _$v.totalPhotos;
_totalCollections = _$v.totalCollections;
_links = _$v.links?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(User other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$User;
}
@override
void update(void Function(UserBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$User build() {
_$User _$result;
try {
_$result = _$v ??
new _$User._(
id: id,
updatedAt: updatedAt,
username: username,
name: name,
portfolioUrl: portfolioUrl,
bio: bio,
location: location,
totalLikes: totalLikes,
totalPhotos: totalPhotos,
totalCollections: totalCollections,
links: _links?.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'links';
_links?.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'User', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,350 @@
// Copyright 2019 The Flutter team. 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/scheduler.dart';
class DataTreeRule extends StatelessWidget {
const DataTreeRule({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 2,
color: Theme.of(context).colorScheme.onBackground.withOpacity(0.1),
);
}
}
class DataTreeInkWell extends StatefulWidget {
const DataTreeInkWell({Key key, this.onTap, this.isSelected, this.child})
: super(key: key);
final VoidCallback onTap;
final bool isSelected;
final Widget child;
@override
_DataTreeInkWellState createState() => _DataTreeInkWellState();
}
class _DataTreeInkWellState extends State<DataTreeInkWell>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation selectionColor;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 100), vsync: this);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
void didUpdateWidget(DataTreeInkWell oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.isSelected) {
controller.forward();
} else {
controller.reverse();
}
}
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
final Animation<Color> backgroundColor = controller
.drive(CurveTween(curve: Curves.fastOutSlowIn))
.drive(ColorTween(
begin: colorScheme.primary.withOpacity(0.0),
end: colorScheme.primary.withOpacity(0.08),
));
final Animation<Color> iconColor = controller
.drive(CurveTween(curve: Curves.fastOutSlowIn))
.drive(ColorTween(
begin: colorScheme.onBackground.withOpacity(0.54),
end: colorScheme.onBackground.withOpacity(0.87),
));
return AnimatedBuilder(
animation: controller,
builder: (context, child) {
return IconTheme(
data: IconThemeData(color: iconColor.value),
child: Container(
color: backgroundColor.value,
child: child,
),
);
},
child: InkWell(
onTap: widget.onTap,
splashFactory: InkRipple.splashFactory,
splashColor: colorScheme.primary.withOpacity(0.14),
highlightColor: Colors.transparent,
child: widget.child,
),
);
}
}
class DataTreeNode extends StatefulWidget {
const DataTreeNode({
Key key,
this.leading,
@required this.title,
this.backgroundColor,
this.onExpansionChanged,
this.onSelectionChanged,
this.children = const <Widget>[],
this.initiallyExpanded = false,
this.indent = 0,
this.height = 36,
}) : assert(initiallyExpanded != null),
assert(indent != null && indent >= 0),
super(key: key);
final Widget leading;
final Widget title;
final ValueChanged<bool> onExpansionChanged;
final ValueChanged<bool> onSelectionChanged;
final List<Widget> children;
final Color backgroundColor;
final bool initiallyExpanded;
final double indent;
final double height;
@override
_DataTreeNodeState createState() => _DataTreeNodeState();
}
class _DataTreeNodeState extends State<DataTreeNode>
with SingleTickerProviderStateMixin {
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
static final Animatable<double> _halfTween =
Tween<double>(begin: 0.0, end: 0.25);
AnimationController _controller;
Animation<double> _iconTurns;
Animation<double> _heightFactor;
bool _isExpanded = false;
bool _isSelected = false;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 200), vsync: this);
_heightFactor = _controller.drive(_easeInTween);
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
_isExpanded = (PageStorage.of(context)?.readState(context) ??
widget.initiallyExpanded) as bool;
if (_isExpanded) {
_controller.value = 1.0;
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _handleNodeTap() {
setState(() {
_isExpanded = !_isExpanded;
if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void>((value) {
if (!mounted) {
return;
}
setState(() {
// Rebuild without widget.children.
});
});
}
PageStorage.of(context)?.writeState(context, _isExpanded);
});
if (widget.onExpansionChanged != null) {
widget.onExpansionChanged(_isExpanded);
}
}
void _handleLeafTap() {
_isSelected = !_isSelected;
if (widget.onSelectionChanged != null) {
widget.onSelectionChanged(_isSelected);
}
}
Widget _buildChildren(BuildContext context, Widget child) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DataTreeInkWell(
onTap: _handleNodeTap,
isSelected: _isExpanded,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(width: widget.indent),
RotationTransition(
turns: _iconTurns,
child: Icon(
Icons.arrow_right,
size: 20,
),
),
const SizedBox(width: 8),
Icon(
Icons.folder,
size: 20,
),
const SizedBox(width: 16),
widget.title,
],
),
),
if (child != null) // If child == null, then this DataNode is closed.
const DataTreeRule(),
if (child != null)
ClipRect(
child: Align(
alignment: Alignment.topLeft,
heightFactor: _heightFactor.value,
child: child,
),
),
],
);
}
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
final Color textColor = colorScheme.onBackground.withOpacity(0.87);
final bool closed = !_isExpanded && _controller.isDismissed;
return widget.children.isEmpty
// Leaf node.
? DataTreeInkWell(
onTap: _handleLeafTap,
isSelected: _isSelected,
child: Row(
children: <Widget>[
SizedBox(width: widget.indent),
Icon(
Icons.web_asset,
size: 20,
),
const SizedBox(width: 16),
DefaultTextStyle(
style: Theme.of(context).textTheme.body1.copyWith(
color: textColor,
),
child: widget.title,
),
],
),
)
// Not a leaf node.
: AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: closed
? null
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
for (int index = 0;
index < (widget.children.length * 2) - 1;
index += 1)
(index % 2 == 1)
? const DataTreeRule()
: widget.children[index ~/ 2],
],
),
);
}
}
// One entry in the multilevel list displayed by this app.
class Entry {
Entry(this.title, [this.children = const <Entry>[]]);
final String title;
final List<Entry> children;
bool isSelected = false;
bool isEnabled = true;
}
// A visualization of one Entry based on DataTreeNode.
class EntryItem extends StatefulWidget {
const EntryItem({Key key, this.entry}) : super(key: key);
final Entry entry;
@override
_EntryItemState createState() => _EntryItemState();
}
class _EntryItemState extends State<EntryItem> {
Widget _buildNodes(Entry root, double indent) {
return DataTreeNode(
key: PageStorageKey<Entry>(root),
onSelectionChanged: (isSelected) {
setState(() {
root.isSelected = isSelected;
});
},
title: Container(
alignment: AlignmentDirectional.centerStart,
height: 36,
child: Text(root.title),
),
indent: indent,
children: root.children.map<Widget>((entry) {
return _buildNodes(entry, indent + 28);
}).toList(),
);
}
@override
Widget build(BuildContext context) {
return _buildNodes(widget.entry, 16);
}
}
class DataTree extends StatelessWidget {
DataTree(this.entries)
: assert(entries != null),
assert(entries.isNotEmpty);
final List<Entry> entries;
@override
Widget build(BuildContext context) => ListView.builder(
itemCount: entries.length * 2 - 1,
itemBuilder: (context, index) {
if (index % 2 == 1) {
return const DataTreeRule();
}
return EntryItem(
entry: entries[index ~/ 2],
);
},
);
}

View File

@@ -0,0 +1,126 @@
// Copyright 2019 The Flutter team. 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/gestures.dart';
import 'package:meta/meta.dart';
import 'package:transparent_image/transparent_image.dart';
import 'package:url_launcher/url_launcher.dart' as url_launcher;
import '../../unsplash_access_key.dart';
import '../unsplash/photo.dart';
final _unsplashHomepage = Uri.encodeFull(
'https://unsplash.com/?utm_source=$unsplashAppName&utm_medium=referral');
typedef PhotoDetailsPhotoSaveCallback = void Function(Photo);
class PhotoDetails extends StatefulWidget {
const PhotoDetails({
@required this.photo,
@required this.onPhotoSave,
});
final Photo photo;
final PhotoDetailsPhotoSaveCallback onPhotoSave;
@override
_PhotoDetailsState createState() => _PhotoDetailsState();
}
class _PhotoDetailsState extends State<PhotoDetails>
with SingleTickerProviderStateMixin {
Widget _buildPhotoAttribution(BuildContext context) {
return RichText(
text: TextSpan(
style: Theme.of(context).textTheme.body1,
children: [
const TextSpan(text: 'Photo by '),
TextSpan(
text: widget.photo.user.name,
style: const TextStyle(
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
final url = Uri.encodeFull(
'https://unsplash.com/@${widget.photo.user.username}?utm_source=$unsplashAppName&utm_medium=referral');
if (await url_launcher.canLaunch(url)) {
await url_launcher.launch(url);
}
},
),
const TextSpan(text: ' on '),
TextSpan(
text: 'Unsplash',
style: const TextStyle(
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
if (await url_launcher.canLaunch(_unsplashHomepage)) {
await url_launcher.launch(_unsplashHomepage);
}
},
),
],
),
);
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 16),
Card(
shape: ContinuousRectangleBorder(
side: BorderSide(color: Colors.black12),
borderRadius: BorderRadius.circular(4),
),
child: AnimatedSize(
vsync: this,
duration: Duration(milliseconds: 750),
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 40),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: 400,
minHeight: 400,
),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: widget.photo.urls.small,
),
),
),
),
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.only(left: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_buildPhotoAttribution(context),
const SizedBox(width: 8),
IconButton(
visualDensity: VisualDensity.compact,
icon: Icon(Icons.cloud_download),
onPressed: () => widget.onPhotoSave(widget.photo),
),
],
),
),
const SizedBox(height: 48),
],
),
),
);
}
}

View File

@@ -0,0 +1,70 @@
// Copyright 2019 The Flutter team. 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';
typedef PhotoSearchDialogCallback = void Function(String searchQuery);
class PhotoSearchDialog extends StatefulWidget {
const PhotoSearchDialog(this.callback);
final PhotoSearchDialogCallback callback;
@override
State<PhotoSearchDialog> createState() => _PhotoSearchDialogState();
}
class _PhotoSearchDialogState extends State<PhotoSearchDialog> {
final _controller = TextEditingController();
bool _searchEnabled = false;
@override
void initState() {
super.initState();
_controller.addListener(() {
setState(() {
_searchEnabled = _controller.text.isNotEmpty;
});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => AlertDialog(
title: const Text('Photo Search'),
content: TextField(
autofocus: true,
controller: _controller,
decoration: const InputDecoration(
hintText: 'Search query',
),
onSubmitted: (content) {
if (content.isNotEmpty) {
widget.callback(content);
Navigator.of(context).pop();
}
},
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'.toUpperCase()),
),
FlatButton(
onPressed: _searchEnabled
? () {
widget.callback(_controller.text);
Navigator.of(context).pop();
}
: null,
child: Text('Search'.toUpperCase()),
),
],
);
}

View File

@@ -0,0 +1,194 @@
// Copyright 2019 The Chromium 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 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
/// A widget that takes two children, lays them out along [axis], and allows
/// the user to resize them.
///
/// The user can customize the amount of space allocated to each child by
/// dragging a divider between them.
///
/// [initialFirstFraction] defines how much space to give the [firstChild]
/// when first building this widget. [secondChild] will take the remaining
/// space.
///
/// The user can drag the widget with key [dividerKey] to change
/// the space allocated between [firstChild] and [secondChild].
// TODO(djshuckerow): introduce support for a minimum fraction a child
// is allowed.
class Split extends StatefulWidget {
/// Builds a split oriented along [axis].
const Split({
Key key,
@required this.axis,
@required this.firstChild,
@required this.secondChild,
double initialFirstFraction,
}) : initialFirstFraction = initialFirstFraction ?? 0.5,
assert(axis != null),
assert(firstChild != null),
assert(secondChild != null),
super(key: key);
/// The main axis the children will lay out on.
///
/// If [Axis.horizontal], the children will be placed in a [Row]
/// and they will be horizontally resizable.
///
/// If [Axis.vertical], the children will be placed in a [Column]
/// and they will be vertically resizable.
///
/// Cannot be null.
final Axis axis;
/// The child that will be laid out first along [axis].
final Widget firstChild;
/// The child that will be laid out last along [axis].
final Widget secondChild;
/// The fraction of the layout to allocate to [firstChild].
///
/// [secondChild] will receive a fraction of `1 - initialFirstFraction`.
final double initialFirstFraction;
/// The key passed to the divider between [firstChild] and [secondChild].
///
/// Visible to grab it in tests.
@visibleForTesting
Key get dividerKey => Key('$this dividerKey');
/// The size of the divider between [firstChild] and [secondChild] in
/// logical pixels (dp, not px).
static const double dividerMainAxisSize = 10;
static Axis axisFor(BuildContext context, double horizontalAspectRatio) {
final screenSize = MediaQuery.of(context).size;
final aspectRatio = screenSize.width / screenSize.height;
if (aspectRatio >= horizontalAspectRatio) {
return Axis.horizontal;
}
return Axis.vertical;
}
@override
State<StatefulWidget> createState() => _SplitState();
}
class _SplitState extends State<Split> {
double firstFraction;
double get secondFraction => 1 - firstFraction;
bool get isHorizontal => widget.axis == Axis.horizontal;
@override
void initState() {
super.initState();
firstFraction = widget.initialFirstFraction;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: _buildLayout);
}
Widget _buildLayout(BuildContext context, BoxConstraints constraints) {
final width = constraints.maxWidth;
final height = constraints.maxHeight;
final axisSize = isHorizontal ? width : height;
final crossAxisSize = isHorizontal ? height : width;
const halfDivider = Split.dividerMainAxisSize / 2.0;
// Determine what fraction to give each child, including enough space to
// display the divider.
double firstSize = axisSize * firstFraction;
double secondSize = axisSize * secondFraction;
// Clamp the sizes to be sure there is enough space for the dividers.
firstSize = firstSize.clamp(halfDivider, axisSize - halfDivider) as double;
secondSize =
secondSize.clamp(halfDivider, axisSize - halfDivider) as double;
// Remove space from each child to place the divider in the middle.
firstSize = firstSize - halfDivider;
secondSize = secondSize - halfDivider;
void updateSpacing(DragUpdateDetails dragDetails) {
final delta = isHorizontal ? dragDetails.delta.dx : dragDetails.delta.dy;
final fractionalDelta = delta / axisSize;
setState(() {
// Update the fraction of space consumed by the children,
// being sure not to allocate any negative space.
firstFraction += fractionalDelta;
firstFraction = firstFraction.clamp(0.0, 1.0) as double;
});
}
// TODO(https://github.com/flutter/flutter/issues/43747): use an icon.
// The material icon for a drag handle is not currently available.
// For now, draw an indicator that is 3 lines running in the direction
// of the main axis, like a hamburger menu.
// TODO(https://github.com/flutter/devtools/issues/1265): update mouse
// to indicate that this is resizable.
final dragIndicator = Flex(
direction: isHorizontal ? Axis.vertical : Axis.horizontal,
mainAxisSize: MainAxisSize.min,
children: [
for (var i = 0; i < min(crossAxisSize / 6.0, 3).floor(); i++)
Padding(
padding: EdgeInsets.symmetric(
vertical: isHorizontal ? 2.0 : 0.0,
horizontal: isHorizontal ? 0.0 : 2.0,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).dividerColor,
borderRadius: BorderRadius.circular(Split.dividerMainAxisSize),
),
child: SizedBox(
height: isHorizontal ? 2.0 : Split.dividerMainAxisSize - 2.0,
width: isHorizontal ? Split.dividerMainAxisSize - 2.0 : 2.0,
),
),
),
],
);
final children = [
SizedBox(
width: isHorizontal ? firstSize : width,
height: isHorizontal ? height : firstSize,
child: widget.firstChild,
),
GestureDetector(
key: widget.dividerKey,
behavior: HitTestBehavior.translucent,
onHorizontalDragUpdate: isHorizontal ? updateSpacing : null,
onVerticalDragUpdate: isHorizontal ? null : updateSpacing,
// DartStartBehavior.down is needed to keep the mouse pointer stuck to
// the drag bar. There still appears to be a few frame lag before the
// drag action triggers which is't ideal but isn't a launch blocker.
dragStartBehavior: DragStartBehavior.down,
child: SizedBox(
width: isHorizontal ? Split.dividerMainAxisSize : width,
height: isHorizontal ? height : Split.dividerMainAxisSize,
child: Center(
child: dragIndicator,
),
),
),
SizedBox(
width: isHorizontal ? secondSize : width,
height: isHorizontal ? height : secondSize,
child: widget.secondChild,
),
];
return Flex(direction: widget.axis, children: children);
}
}

View File

@@ -0,0 +1,9 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO: Retrieve an API Access Key from https://unsplash.com/developers
const String unsplashAccessKey = '';
// The application name for the above API Access Key.
const unsplashAppName = '';