Desktop photo search (#174)

pull/177/head
Brett Morgan 5 years ago committed by GitHub
parent 8c27a25d50
commit f07b4a90d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,37 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 7caef218b55acac803aa67e7393e97f75ec70c5c
channel: master
project_type: app

@ -0,0 +1,56 @@
# Photo Search app
This macOS application enables you to search [Unsplash](https://unsplash.com/)
for photographs that interest you. To use it, you need to add an
**Access Key** from [Unsplash API](https://unsplash.com/developers) to
[unsplash_access_key.dart](lib/unsplash_access_key.dart).
## A quick tour of the code
This Flutter project builds a desktop application. It utilises the following
desktop specific plugins:
- [file_choser] to enable the application user to select where to save a photo
from the Unsplash API.
- [menubar] for exposing Image Search functionality through the menu bar.
- [url_launcher_fde] and [url_launcher] plugin, which are used to open external links.
The Unsplash API client entry point is in the [Unsplash] class, and is built
atop [http], [built_value] and [built_collection] for JSON Rest API access.
The [DataTreeNode] and widget family, along with the [Split] widget capture
desktop file explorer master/detail view idioms.
## macOS Network and File entitlements
To access the network, macOS requires applications enable the
[com.apple.security.network.client entitlement][macOS-client]. For this
sample, this entitlement is required to access the Unsplash API.
Likewise, to save a Photo to the local file system using the `file_choser` plugin requires the
[com.apple.security.files.user-selected.read-write entitlement][macOS-read-write].
Please see [macOS Signing and Security][macOS-security] for more detail.
## Flutter Desktop is not in Flutter Stable Release Channel
This sample is an initial preview, intended to enable developers to preview what is
under development. As such, it is currently only available for use on the `master` channel
of Flutter. Please see [Flutter build release channels][flutter_channels] for more detail,
and how to switch between Flutter release channels.
[DataTreeNode]: lib/src/widgets/data_tree.dart
[Split]: lib/src/widgets/split.dart
[Unsplash]: lib/src/unsplash/unsplash.dart
[built_collection]: https://pub.dev/packages/built_collection
[built_value]: https://pub.dev/packages/built_value
[file_choser]: https://github.com/google/flutter-desktop-embedding/tree/master/plugins/file_chooser
[flutter_channels]: https://github.com/flutter/flutter/wiki/Flutter-build-release-channels
[http]: https://pub.dev/packages/http
[macOS-client]: https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_network_client
[macOS-read-write]: https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_files_user-selected_read-write
[macOS-security]: https://github.com/google/flutter-desktop-embedding/blob/master/macOS-Security.md
[menubar]: https://github.com/google/flutter-desktop-embedding/tree/master/plugins/menubar
[url_launcher]: https://pub.dev/packages/url_launcher
[url_launcher_fde]: https://github.com/google/flutter-desktop-embedding/tree/master/plugins/flutter_plugins/url_launcher_fde

@ -0,0 +1,30 @@
include: package:pedantic/analysis_options.1.8.0.yaml
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
linter:
rules:
- avoid_types_on_closure_parameters
- avoid_void_async
- await_only_futures
- camel_case_types
- cancel_subscriptions
- close_sinks
- constant_identifier_names
- control_flow_in_finally
- empty_statements
- hash_and_equals
- implementation_imports
- non_constant_identifier_names
- package_api_docs
- package_names
- package_prefixed_library_names
- test_types_in_equals
- throw_in_finally
- unnecessary_brace_in_string_interps
- unnecessary_getters_setters
- unnecessary_new
- unnecessary_statements

@ -0,0 +1,15 @@
targets:
$default:
builders:
built_value_generator|built_value:
enabled: true
builders:
built_value:
target: ":built_value_generator"
import: "package:built_value_generator/builder.dart"
builder_factories: ["builtValue"]
build_extensions: {".dart": [".built_value.g.part"]}
auto_apply: dependents
build_to: cache
applies_builders: ["source_gen|combining_builder"]

@ -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),
),
);
}
}

@ -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);
}

@ -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;
}

@ -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

@ -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();

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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';
}
}

@ -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;
}

@ -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

@ -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;
}

@ -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

@ -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],
);
},
);
}

@ -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),
],
),
),
);
}
}

@ -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()),
),
],
);
}

@ -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);
}
}

@ -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 = '';

@ -0,0 +1,6 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/xcuserdata/

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

@ -0,0 +1,16 @@
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import file_chooser
import menubar
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileChooserPlugin.register(with: registry.registrar(forPlugin: "FileChooserPlugin"))
MenubarPlugin.register(with: registry.registrar(forPlugin: "MenubarPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}

@ -0,0 +1,82 @@
platform :osx, '10.11'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
def pubspec_supports_macos(file)
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return false;
end
File.foreach(file_abs_path) { |line|
return true if line =~ /^\s*macos:/
}
return false
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
ephemeral_dir = File.join('Flutter', 'ephemeral')
symlink_dir = File.join(ephemeral_dir, '.symlinks')
symlink_plugins_dir = File.join(symlink_dir, 'plugins')
system("rm -rf #{symlink_dir}")
system("mkdir -p #{symlink_plugins_dir}")
# Flutter Pods
generated_xcconfig = parse_KV_file(File.join(ephemeral_dir, 'Flutter-Generated.xcconfig'))
if generated_xcconfig.empty?
puts "Flutter-Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcconfig.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join(symlink_dir, 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'FlutterMacOS', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join(symlink_plugins_dir, p[:name])
File.symlink(p[:path], symlink)
if pubspec_supports_macos(File.join(symlink, 'pubspec.yaml'))
pod p[:name], :path => File.join(symlink, 'macos')
end
}
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true

@ -0,0 +1,34 @@
PODS:
- file_chooser (0.0.2):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- menubar (0.0.2):
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- file_chooser (from `Flutter/ephemeral/.symlinks/plugins/file_chooser/macos`)
- FlutterMacOS (from `Flutter/ephemeral/.symlinks/flutter/darwin-x64`)
- menubar (from `Flutter/ephemeral/.symlinks/plugins/menubar/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
EXTERNAL SOURCES:
file_chooser:
:path: Flutter/ephemeral/.symlinks/plugins/file_chooser/macos
FlutterMacOS:
:path: Flutter/ephemeral/.symlinks/flutter/darwin-x64
menubar:
:path: Flutter/ephemeral/.symlinks/plugins/menubar/macos
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
SPEC CHECKSUMS:
file_chooser: 24432cf5dc836722b05c11c2a0a30d19c3c9b996
FlutterMacOS: 15bea8a44d2fa024068daa0140371c020b4b6ff9
menubar: 4e3d461d62d775540277ce6639acafe2a111a231
url_launcher_macos: 77182d012b6b515c0955d24ed22b38f79b82a99d
PODFILE CHECKSUM: d8ba9b3e9e93c62c74a660b46c6fcb09f03991a7
COCOAPODS: 1.8.4

@ -0,0 +1,656 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; };
33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
990488F4C467BB319BE84EEE /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA9B03A69D73D1FB7426AAD /* Pods_Runner.framework */; };
D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; };
D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */,
33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */,
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
30800270447E6C112F71B5A2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* Photo Search.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Photo Search.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
6874C7348F87E58F46720BF4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
8CA9B03A69D73D1FB7426AAD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; };
F2B5091A1DEA6D9237ACA748 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D73912F022F37F9E000D13A0 /* App.framework in Frameworks */,
33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */,
990488F4C467BB319BE84EEE /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
BF229184A4E8E7AA3EE10F9D /* Pods */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* Photo Search.app */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
D73912EF22F37F9E000D13A0 /* App.framework */,
33D1A10322148B71006C7A3E /* FlutterMacOS.framework */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
BF229184A4E8E7AA3EE10F9D /* Pods */ = {
isa = PBXGroup;
children = (
F2B5091A1DEA6D9237ACA748 /* Pods-Runner.debug.xcconfig */,
30800270447E6C112F71B5A2 /* Pods-Runner.release.xcconfig */,
6874C7348F87E58F46720BF4 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
8CA9B03A69D73D1FB7426AAD /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
4DC401FC85DF0A3149D2CECF /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
A00F8189E692D536E087EEAD /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* Photo Search.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1120;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n";
};
4DC401FC85DF0A3149D2CECF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A00F8189E692D536E087EEAD /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/stuartmorgan/src/embedder-opensource/flutter-desktop-embedding/example/macos/Runner.xcodeproj">
</FileRef>
</Workspace>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1120"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Photo Search.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Photo Search.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00380F9121DF178D00097171"
BuildableName = "RunnerUITests.xctest"
BlueprintName = "RunnerUITests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Photo Search.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Photo Search.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

@ -0,0 +1,13 @@
// 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 Cocoa
import FlutterMacOS
@NSApplicationMain
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}

@ -0,0 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

@ -0,0 +1,339 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>

@ -0,0 +1,14 @@
// Application-level settings for the Runner target.
//
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = Photo Search
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.photoSearch
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2019 com.example. All rights reserved.

@ -0,0 +1,2 @@
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"

@ -0,0 +1,2 @@
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"

@ -0,0 +1,13 @@
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

@ -0,0 +1,19 @@
// 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 Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController.init()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

@ -0,0 +1,681 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
analysis_server_lib:
dependency: transitive
description:
name: analysis_server_lib
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.8"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.38.5"
analyzer_plugin:
dependency: transitive
description:
name: analyzer_plugin
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.2"
async:
dependency: "direct dev"
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
build:
dependency: "direct dev"
description:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.2"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.1+1"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.2"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.0"
built_collection:
dependency: "direct main"
description:
name: built_collection
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.0"
built_value:
dependency: "direct main"
description:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.0"
built_value_generator:
dependency: "direct dev"
description:
name: built_value_generator
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3+2"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.11"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
coverage:
dependency: transitive
description:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.3+3"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
file_chooser:
dependency: "direct main"
description:
path: "plugins/file_chooser"
ref: HEAD
resolved-ref: ab3b14f7231289dc66b7ad21c607cb90dd896fc0
url: "https://github.com/google/flutter-desktop-embedding.git"
source: git
version: "0.1.0"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.11"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
front_end:
dependency: transitive
description:
name: front_end
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.27"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
grinder:
dependency: "direct dev"
description:
name: grinder
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.3+1"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.0+3"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0+2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.3"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
intl:
dependency: transitive
description:
name: intl
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.8"
io:
dependency: transitive
description:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1+1"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
kernel:
dependency: transitive
description:
name: kernel
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.27"
logging:
dependency: "direct main"
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.3+2"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.6"
menubar:
dependency: "direct main"
description:
path: "plugins/menubar"
ref: HEAD
resolved-ref: ab3b14f7231289dc66b7ad21c607cb90dd896fc0
url: "https://github.com/google/flutter-desktop-embedding.git"
source: git
version: "0.0.1"
meta:
dependency: "direct main"
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.8"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.6+3"
multi_server_socket:
dependency: transitive
description:
name: multi_server_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1+2"
node_preamble:
dependency: transitive
description:
name: node_preamble
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.8"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
package_resolver:
dependency: transitive
description:
name: package_resolver
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.10"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.4"
pedantic:
dependency: "direct main"
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0+1"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.0"
provider:
dependency: "direct main"
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.2"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.5"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
shelf_static:
dependency: transitive
description:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.8"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: "direct dev"
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4+6"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.5"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.8"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.5"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.20"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
test:
dependency: "direct dev"
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.4"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.11"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.15"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+2"
transparent_image:
dependency: "direct main"
description:
name: transparent_image
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
tuneup:
dependency: "direct dev"
description:
name: tuneup
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.6+1"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "5.3.0"
url_launcher_macos:
dependency: "direct main"
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0+1"
uuid:
dependency: "direct main"
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
vm_service:
dependency: transitive
description:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.7+13"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.5.0"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
sdks:
dart: ">=2.7.0-dev <3.0.0"
flutter: ">=1.13.1-pre <2.0.0"

@ -0,0 +1,45 @@
name: desktop_photo_search
description: Search for Photos, using the Unsplash API.
version: 1.0.0+1
environment:
sdk: ^2.7.0-dev
flutter: ^1.13.1-pre
dependencies:
flutter:
sdk: flutter
built_collection: ^4.3.0
built_value: ^7.0.0
cupertino_icons: ^0.1.2
file_chooser:
git:
url: https://github.com/google/flutter-desktop-embedding.git
path: plugins/file_chooser
logging: ^0.11.3+2
menubar:
git:
url: https://github.com/google/flutter-desktop-embedding.git
path: plugins/menubar
meta: ^1.1.8
pedantic: ^1.8.0
provider: ^3.2.0
transparent_image: ^1.0.0
uuid: ^2.0.4
url_launcher: ^5.3.0
url_launcher_macos: ^0.0.1
dev_dependencies:
flutter_test:
sdk: flutter
async: ^2.4.0
build: ^1.2.2
build_runner: ^1.7.2
built_value_generator: ^7.0.0
grinder: ^0.8.3
source_gen: ^0.9.4
test: ^1.9.4
tuneup: ^0.3.6
flutter:
uses-material-design: true

@ -0,0 +1,347 @@
// 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:desktop_photo_search/src/unsplash/photo.dart';
import 'package:desktop_photo_search/src/unsplash/search_photos_response.dart';
import 'package:desktop_photo_search/src/unsplash/unsplash.dart';
import 'package:desktop_photo_search/src/unsplash/user.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';
import 'package:test/test.dart';
void main() {
test('Photo.fromJson', () {
const input = '''
{
"id": "Dwu85P9SOIk",
"created_at": "2016-05-03T11:00:28-04:00",
"updated_at": "2016-07-10T11:00:01-05:00",
"width": 2448,
"height": 3264,
"color": "#6E633A",
"downloads": 1345,
"likes": 24,
"liked_by_user": false,
"description": "A man drinking a coffee.",
"exif": {
"make": "Canon",
"model": "Canon EOS 40D",
"exposure_time": "0.011111111111111112",
"aperture": "4.970854",
"focal_length": "37",
"iso": 100
},
"location": {
"city": "Montreal",
"country": "Canada",
"position": {
"latitude": 45.4732984,
"longitude": -73.6384879
}
},
"tags": [
{ "title": "man" },
{ "title": "drinking" },
{ "title": "coffee" }
],
"current_user_collections": [
{
"id": 206,
"title": "Makers: Cat and Ben",
"published_at": "2016-01-12T18:16:09-05:00",
"updated_at": "2016-07-10T11:00:01-05:00",
"cover_photo": null,
"user": null
}
],
"urls": {
"raw": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d",
"full": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg",
"regular": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg&w=1080&fit=max",
"small": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg&w=400&fit=max",
"thumb": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg&w=200&fit=max"
},
"links": {
"self": "https://api.unsplash.com/photos/Dwu85P9SOIk",
"html": "https://unsplash.com/photos/Dwu85P9SOIk",
"download": "https://unsplash.com/photos/Dwu85P9SOIk/download",
"download_location": "https://api.unsplash.com/photos/Dwu85P9SOIk/download"
},
"user": {
"id": "QPxL2MGqfrw",
"updated_at": "2016-07-10T11:00:01-05:00",
"username": "exampleuser",
"name": "Joe Example",
"portfolio_url": "https://example.com/",
"bio": "Just an everyday Joe",
"location": "Montreal",
"total_likes": 5,
"total_photos": 10,
"total_collections": 13,
"links": {
"self": "https://api.unsplash.com/users/exampleuser",
"html": "https://unsplash.com/exampleuser",
"photos": "https://api.unsplash.com/users/exampleuser/photos",
"likes": "https://api.unsplash.com/users/exampleuser/likes",
"portfolio": "https://api.unsplash.com/users/exampleuser/portfolio"
}
}
}
''';
final photo = Photo.fromJson(input);
expect(photo.id, 'Dwu85P9SOIk');
expect(photo.createdAt, '2016-05-03T11:00:28-04:00');
expect(photo.updatedAt, '2016-07-10T11:00:01-05:00');
expect(photo.width, 2448);
expect(photo.height, 3264);
expect(photo.color, '#6E633A');
expect(photo.downloads, 1345);
expect(photo.likedByUser, false);
expect(photo.exif.make, 'Canon');
expect(photo.exif.iso, 100);
expect(photo.location.city, 'Montreal');
expect(photo.location.country, 'Canada');
expect(photo.location.position.latitude, 45.4732984);
expect(photo.location.position.longitude, -73.6384879);
});
test('User.fromJson', () {
const input = '''
{
"id": "pXhwzz1JtQU",
"updated_at": "2016-07-10T11:00:01-05:00",
"username": "jimmyexample",
"name": "James Example",
"first_name": "James",
"last_name": "Example",
"instagram_username": "instantgrammer",
"twitter_username": "jimmy",
"portfolio_url": null,
"bio": "The user's bio",
"location": "Montreal, Qc",
"total_likes": 20,
"total_photos": 10,
"total_collections": 5,
"followed_by_user": false,
"followers_count": 300,
"following_count": 25,
"downloads": 225974,
"profile_image": {
"small": "https://images.unsplash.com/face-springmorning.jpg?q=80&fm=jpg&crop=faces&fit=crop&h=32&w=32",
"medium": "https://images.unsplash.com/face-springmorning.jpg?q=80&fm=jpg&crop=faces&fit=crop&h=64&w=64",
"large": "https://images.unsplash.com/face-springmorning.jpg?q=80&fm=jpg&crop=faces&fit=crop&h=128&w=128"
},
"badge": {
"title": "Book contributor",
"primary": true,
"slug": "book-contributor",
"link": "https://book.unsplash.com"
},
"links": {
"self": "https://api.unsplash.com/users/jimmyexample",
"html": "https://unsplash.com/jimmyexample",
"photos": "https://api.unsplash.com/users/jimmyexample/photos",
"likes": "https://api.unsplash.com/users/jimmyexample/likes",
"portfolio": "https://api.unsplash.com/users/jimmyexample/portfolio"
}
}
''';
final user = User.fromJson(input);
expect(user.id, 'pXhwzz1JtQU');
});
test('SearchPhotosResponse.fromJson', () {
const input = '''
{
"total": 133,
"total_pages": 7,
"results": [
{
"id": "eOLpJytrbsQ",
"created_at": "2014-11-18T14:35:36-05:00",
"width": 4000,
"height": 3000,
"color": "#A7A2A1",
"likes": 286,
"liked_by_user": false,
"description": "A man drinking a coffee.",
"user": {
"id": "Ul0QVz12Goo",
"username": "ugmonk",
"name": "Jeff Sheldon",
"first_name": "Jeff",
"last_name": "Sheldon",
"instagram_username": "instantgrammer",
"twitter_username": "ugmonk",
"portfolio_url": "http://ugmonk.com/",
"profile_image": {
"small": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32&s=7cfe3b93750cb0c93e2f7caec08b5a41",
"medium": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=64&w=64&s=5a9dc749c43ce5bd60870b129a40902f",
"large": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=128&w=128&s=32085a077889586df88bfbe406692202"
},
"links": {
"self": "https://api.unsplash.com/users/ugmonk",
"html": "http://unsplash.com/@ugmonk",
"photos": "https://api.unsplash.com/users/ugmonk/photos",
"likes": "https://api.unsplash.com/users/ugmonk/likes"
}
},
"current_user_collections": [],
"urls": {
"raw": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f",
"full": "https://hd.unsplash.com/photo-1416339306562-f3d12fefd36f",
"regular": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=92f3e02f63678acc8416d044e189f515",
"small": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&s=263af33585f9d32af39d165b000845eb",
"thumb": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=8aae34cf35df31a592f0bef16e6342ef"
},
"links": {
"self": "https://api.unsplash.com/photos/eOLpJytrbsQ",
"html": "http://unsplash.com/photos/eOLpJytrbsQ",
"download": "http://unsplash.com/photos/eOLpJytrbsQ/download"
}
}
]
}
''';
final response = SearchPhotosResponse.fromJson(input);
expect(response.total, 133);
expect(response.totalPages, 7);
expect(response.results[0].id, 'eOLpJytrbsQ');
expect(response.results[0].user.id, 'Ul0QVz12Goo');
});
group('Unsplash API client', () {
test('handles success', () async {
const searchPhotosResponseBody = '''
{
"total": 133,
"total_pages": 7,
"results": [
{
"id": "eOLpJytrbsQ",
"created_at": "2014-11-18T14:35:36-05:00",
"width": 4000,
"height": 3000,
"color": "#A7A2A1",
"likes": 286,
"liked_by_user": false,
"description": "A man drinking a coffee.",
"user": {
"id": "Ul0QVz12Goo",
"username": "ugmonk",
"name": "Jeff Sheldon",
"first_name": "Jeff",
"last_name": "Sheldon",
"instagram_username": "instantgrammer",
"twitter_username": "ugmonk",
"portfolio_url": "http://ugmonk.com/",
"profile_image": {
"small": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32&s=7cfe3b93750cb0c93e2f7caec08b5a41",
"medium": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=64&w=64&s=5a9dc749c43ce5bd60870b129a40902f",
"large": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=128&w=128&s=32085a077889586df88bfbe406692202"
},
"links": {
"self": "https://api.unsplash.com/users/ugmonk",
"html": "http://unsplash.com/@ugmonk",
"photos": "https://api.unsplash.com/users/ugmonk/photos",
"likes": "https://api.unsplash.com/users/ugmonk/likes"
}
},
"current_user_collections": [],
"urls": {
"raw": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f",
"full": "https://hd.unsplash.com/photo-1416339306562-f3d12fefd36f",
"regular": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=92f3e02f63678acc8416d044e189f515",
"small": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&s=263af33585f9d32af39d165b000845eb",
"thumb": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=8aae34cf35df31a592f0bef16e6342ef"
},
"links": {
"self": "https://api.unsplash.com/photos/eOLpJytrbsQ",
"html": "http://unsplash.com/photos/eOLpJytrbsQ",
"download": "http://unsplash.com/photos/eOLpJytrbsQ/download"
}
}
]
}
''';
final httpClient = MockClient((req) async {
return Response(
searchPhotosResponseBody,
200,
request: req,
headers: {'content-type': 'application/json'},
);
});
final unsplashClient = Unsplash(
accessKey: 'not-an-access-key',
httpClient: httpClient,
);
final response = await unsplashClient.searchPhotos(query: 'red');
expect(response.total, 133);
expect(response.totalPages, 7);
expect(response.results[0].id, 'eOLpJytrbsQ');
expect(response.results[0].user.id, 'Ul0QVz12Goo');
});
test('handles failure', () async {
const apiError =
'{"errors":["OAuth error: The access token is invalid"]}';
final httpClient = MockClient((req) async {
return Response(
apiError,
401,
request: req,
headers: {'content-type': 'application/json'},
);
});
final unsplashClient = Unsplash(
accessKey: 'not-an-access-key',
httpClient: httpClient,
);
try {
await unsplashClient.searchPhotos(query: 'red');
fail('UnsplashException should have been thrown');
} on UnsplashException catch (e) {
expect(e.toString(),
'UnsplashException: OAuth error: The access token is invalid');
}
});
test('handles broken JSON', () async {
const apiError = '{"tot'; // truncated JSON.
final httpClient = MockClient((req) async {
return Response(
apiError,
401,
request: req,
headers: {'content-type': 'application/json'},
);
});
final unsplashClient = Unsplash(
accessKey: 'not-an-access-key',
httpClient: httpClient,
);
try {
await unsplashClient.searchPhotos(query: 'red');
fail('UnsplashException should have been thrown');
} on UnsplashException catch (e) {
expect(e.toString(),
'UnsplashException: Invalid JSON received');
}
});
});
}

@ -0,0 +1,130 @@
// 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:desktop_photo_search/src/unsplash/photo.dart';
import 'package:flutter/material.dart';
import 'package:desktop_photo_search/src/model/photo_search_model.dart';
import 'package:desktop_photo_search/src/unsplash/search_photos_response.dart';
import 'package:desktop_photo_search/src/unsplash/unsplash.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
class FakeUnsplash implements Unsplash {
static const searchPhotosResponse = '''
{
"total": 133,
"total_pages": 7,
"results": [
{
"id": "eOLpJytrbsQ",
"created_at": "2014-11-18T14:35:36-05:00",
"width": 4000,
"height": 3000,
"color": "#A7A2A1",
"likes": 286,
"liked_by_user": false,
"description": "A man drinking a coffee.",
"user": {
"id": "Ul0QVz12Goo",
"username": "ugmonk",
"name": "Jeff Sheldon",
"first_name": "Jeff",
"last_name": "Sheldon",
"instagram_username": "instantgrammer",
"twitter_username": "ugmonk",
"portfolio_url": "http://ugmonk.com/",
"profile_image": {
"small": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32&s=7cfe3b93750cb0c93e2f7caec08b5a41",
"medium": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=64&w=64&s=5a9dc749c43ce5bd60870b129a40902f",
"large": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=128&w=128&s=32085a077889586df88bfbe406692202"
},
"links": {
"self": "https://api.unsplash.com/users/ugmonk",
"html": "http://unsplash.com/@ugmonk",
"photos": "https://api.unsplash.com/users/ugmonk/photos",
"likes": "https://api.unsplash.com/users/ugmonk/likes"
}
},
"current_user_collections": [],
"urls": {
"raw": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f",
"full": "https://hd.unsplash.com/photo-1416339306562-f3d12fefd36f",
"regular": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=92f3e02f63678acc8416d044e189f515",
"small": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&s=263af33585f9d32af39d165b000845eb",
"thumb": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=8aae34cf35df31a592f0bef16e6342ef"
},
"links": {
"self": "https://api.unsplash.com/photos/eOLpJytrbsQ",
"html": "http://unsplash.com/photos/eOLpJytrbsQ",
"download": "http://unsplash.com/photos/eOLpJytrbsQ/download"
}
}
]
}
''';
@override
Future<SearchPhotosResponse> searchPhotos(
{String query,
num page = 1,
num perPage = 10,
List<num> collections = const [],
SearchPhotosOrientation orientation}) async {
return SearchPhotosResponse.fromJson(searchPhotosResponse);
}
@override
Future<Uint8List> download(Photo photo) {
throw UnimplementedError();
}
}
const fabKey = Key('fab');
class PhotoSearchModelTester extends StatelessWidget {
const PhotoSearchModelTester(this.query);
final String query;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FlatButton(
key: fabKey,
onPressed: () async {
await Provider.of<PhotoSearchModel>(context).addSearch(query);
},
child: const Text('Search for a Photo'),
),
);
}
}
void main() {
group('search_list', () {
testWidgets('starts empty', (tester) async {
final unsplashSearches = PhotoSearchModel(FakeUnsplash());
final testWidget = ChangeNotifierProvider<PhotoSearchModel>(
create: (context) => unsplashSearches,
child: const PhotoSearchModelTester('clouds'),
);
await tester.pumpWidget(testWidget);
expect(unsplashSearches.entries.length, 0);
});
testWidgets('addSearch adds searches', (tester) async {
final unsplashSearches = PhotoSearchModel(FakeUnsplash());
final testWidget = ChangeNotifierProvider<PhotoSearchModel>(
create: (context) => unsplashSearches,
child: const PhotoSearchModelTester('clouds'),
);
await tester.pumpWidget(testWidget);
await tester.tap(find.byKey(fabKey));
await tester.tap(find.byKey(fabKey));
await tester.pumpAndSettle();
expect(unsplashSearches.entries.length, 2);
});
});
}

@ -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:async';
import 'dart:convert';
import 'dart:io';
import 'package:async/async.dart' show StreamGroup;
import 'package:grinder/grinder.dart';
void main(List<String> args) => grind(args);
@DefaultTask()
@Depends(pubGet, generateJsonBindings, analyzeSource, test)
void build() {}
@Task()
Future<void> pubGet() async => _logProcessOutput(
Process.start(
'flutter',
['pub', 'get'],
),
);
@Task()
Future<void> generateJsonBindings() async => _logProcessOutput(
Process.start(
'flutter',
['pub', 'run', 'build_runner', 'build', '--delete-conflicting-outputs'],
),
);
@Task()
Future<void> watch() async => _logProcessOutput(
Process.start(
'flutter',
['pub', 'run', 'build_runner', 'watch'],
),
);
@Task()
Future<void> analyzeSource() async => _logProcessOutput(
Process.start(
'flutter',
['pub', 'run', 'tuneup'],
),
);
@Task()
Future<void> test() async => _logProcessOutput(
Process.start(
'flutter',
['test'],
),
);
@Task()
Future<void> clean() => _logProcessOutput(
Process.start(
'flutter',
['clean'],
),
);
Future<void> _logProcessOutput(Future<Process> proc) async {
final process = await proc;
final output = StreamGroup.merge([process.stdout, process.stderr]);
await for (final message in output) {
log(utf8.decode(message));
}
}
Loading…
Cancel
Save