1
0
mirror of https://github.com/flutter/samples.git synced 2026-04-05 11:11:23 +00:00

Migrate desktop_photo_search to top level (#1002)

This commit is contained in:
Brett Morgan
2022-02-04 08:33:53 +10:00
committed by GitHub
parent 93bf3263c5
commit 9c02a0fa09
208 changed files with 9408 additions and 535 deletions

View File

@@ -0,0 +1,51 @@
// 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 '../unsplash/photo.dart';
import '../unsplash/unsplash.dart';
import 'search.dart';
class SearchEntry {
const SearchEntry(this.query, this.photos, this.model);
final String query;
final List<Photo> photos;
final PhotoSearchModel model;
}
class PhotoSearchModel extends ChangeNotifier {
PhotoSearchModel(this._client);
final Unsplash _client;
List<SearchEntry> get entries => List.unmodifiable(_entries);
final List<SearchEntry> _entries = [];
Photo? get selectedPhoto => _selectedPhoto;
set selectedPhoto(Photo? photo) {
_selectedPhoto = photo;
notifyListeners();
}
Photo? _selectedPhoto;
Future<void> addSearch(String query) async {
final result = await _client.searchPhotos(
query: query,
orientation: SearchPhotosOrientation.portrait,
);
final search = Search((s) {
s
..query = query
..results.addAll(result!.results);
});
_entries.add(SearchEntry(query, search.results.toList(), this));
notifyListeners();
}
Future<Uint8List> download({required Photo photo}) => _client.download(photo);
}

View File

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

View File

@@ -0,0 +1,166 @@
// 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 Object? 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<Object?>);
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._({required this.query, required this.results}) : super._() {
BuiltValueNullFieldError.checkNotNull(query, 'Search', 'query');
BuiltValueNullFieldError.checkNotNull(results, '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 {
final $v = _$v;
if ($v != null) {
_query = $v.query;
_results = $v.results.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(Search other) {
ArgumentError.checkNotNull(other, '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: BuiltValueNullFieldError.checkNotNull(
query, 'Search', 'query'),
results: results.build());
} catch (_) {
late 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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,27 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
import 'model/search.dart';
import 'unsplash/api_error.dart';
import 'unsplash/current_user_collections.dart';
import 'unsplash/exif.dart';
import 'unsplash/links.dart';
import 'unsplash/location.dart';
import 'unsplash/photo.dart';
import 'unsplash/position.dart';
import 'unsplash/search_photos_response.dart';
import 'unsplash/tags.dart';
import 'unsplash/urls.dart';
import 'unsplash/user.dart';
part 'serializers.g.dart';
//add all of the built value types that require serialization
@SerializersFor([Search, ApiError, Photo, SearchPhotosResponse])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

View File

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

View File

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

View File

@@ -0,0 +1,146 @@
// 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?>[];
Object? value;
value = object.errors;
if (value != null) {
result
..add('errors')
..add(serializers.serialize(value,
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 Object? value = iterator.current;
switch (key) {
case 'errors':
result.errors.replace(serializers.deserialize(value,
specifiedType: const FullType(
BuiltList, const [const FullType(String)]))!
as BuiltList<Object?>);
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._();
@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 {
final $v = _$v;
if ($v != null) {
_errors = $v.errors?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(ApiError other) {
ArgumentError.checkNotNull(other, '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 (_) {
late 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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,46 @@
// 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;
@BuiltValueField(wireName: 'title')
String? get title;
@BuiltValueField(wireName: 'published_at')
String? get publishedAt;
@BuiltValueField(wireName: 'updated_at')
String? get updatedAt;
String toJson() {
return json.encode(
serializers.serializeWith(CurrentUserCollections.serializer, this));
}
static CurrentUserCollections? fromJson(String jsonString) {
return serializers.deserializeWith(
CurrentUserCollections.serializer, json.decode(jsonString));
}
static Serializer<CurrentUserCollections> get serializer =>
_$currentUserCollectionsSerializer;
}

View File

@@ -0,0 +1,210 @@
// 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)),
];
Object? value;
value = object.title;
if (value != null) {
result
..add('title')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.publishedAt;
if (value != null) {
result
..add('published_at')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.updatedAt;
if (value != null) {
result
..add('updated_at')
..add(serializers.serialize(value,
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 Object? 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._(
{required this.id, this.title, this.publishedAt, this.updatedAt})
: super._() {
BuiltValueNullFieldError.checkNotNull(id, '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 {
final $v = _$v;
if ($v != null) {
_id = $v.id;
_title = $v.title;
_publishedAt = $v.publishedAt;
_updatedAt = $v.updatedAt;
_$v = null;
}
return this;
}
@override
void replace(CurrentUserCollections other) {
ArgumentError.checkNotNull(other, '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: BuiltValueNullFieldError.checkNotNull(
id, 'CurrentUserCollections', '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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,47 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_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._();
@BuiltValueField(wireName: 'make')
String? get make;
@BuiltValueField(wireName: 'model')
String? get model;
@BuiltValueField(wireName: 'exposure_time')
String? get exposureTime;
@BuiltValueField(wireName: 'aperture')
String? get aperture;
@BuiltValueField(wireName: 'focal_length')
String? get focalLength;
@BuiltValueField(wireName: 'iso')
int? get iso;
String toJson() {
return json.encode(serializers.serializeWith(Exif.serializer, this));
}
static Exif? fromJson(String jsonString) {
return serializers.deserializeWith(
Exif.serializer, json.decode(jsonString));
}
static Serializer<Exif> get serializer => _$exifSerializer;
}

View File

@@ -0,0 +1,251 @@
// 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?>[];
Object? value;
value = object.make;
if (value != null) {
result
..add('make')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.model;
if (value != null) {
result
..add('model')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.exposureTime;
if (value != null) {
result
..add('exposure_time')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.aperture;
if (value != null) {
result
..add('aperture')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.focalLength;
if (value != null) {
result
..add('focal_length')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.iso;
if (value != null) {
result
..add('iso')
..add(serializers.serialize(value, 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 Object? 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 {
final $v = _$v;
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) {
ArgumentError.checkNotNull(other, '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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,41 @@
// 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._();
@BuiltValueField(wireName: 'self')
String? get self;
@BuiltValueField(wireName: 'html')
String? get html;
@BuiltValueField(wireName: 'download')
String? get download;
@BuiltValueField(wireName: 'download_location')
String? get downloadLocation;
String toJson() {
return json.encode(serializers.serializeWith(Links.serializer, this));
}
static Links? fromJson(String jsonString) {
return serializers.deserializeWith(
Links.serializer, json.decode(jsonString));
}
static Serializer<Links> get serializer => _$linksSerializer;
}

View File

@@ -0,0 +1,200 @@
// 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?>[];
Object? value;
value = object.self;
if (value != null) {
result
..add('self')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.html;
if (value != null) {
result
..add('html')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.download;
if (value != null) {
result
..add('download')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.downloadLocation;
if (value != null) {
result
..add('download_location')
..add(serializers.serialize(value,
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 Object? 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 {
final $v = _$v;
if ($v != null) {
_self = $v.self;
_html = $v.html;
_download = $v.download;
_downloadLocation = $v.downloadLocation;
_$v = null;
}
return this;
}
@override
void replace(Links other) {
ArgumentError.checkNotNull(other, '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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,39 @@
// 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._();
@BuiltValueField(wireName: 'city')
String? get city;
@BuiltValueField(wireName: 'country')
String? get country;
@BuiltValueField(wireName: 'position')
Position? get position;
String toJson() {
return json.encode(serializers.serializeWith(Location.serializer, this));
}
static Location? fromJson(String jsonString) {
return serializers.deserializeWith(
Location.serializer, json.decode(jsonString));
}
static Serializer<Location> get serializer => _$locationSerializer;
}

View File

@@ -0,0 +1,187 @@
// 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?>[];
Object? value;
value = object.city;
if (value != null) {
result
..add('city')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.country;
if (value != null) {
result
..add('country')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.position;
if (value != null) {
result
..add('position')
..add(serializers.serialize(value,
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 Object? 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 {
final $v = _$v;
if ($v != null) {
_city = $v.city;
_country = $v.country;
_position = $v.position?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(Location other) {
ArgumentError.checkNotNull(other, '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 (_) {
late 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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,88 @@
// 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;
@BuiltValueField(wireName: 'created_at')
String? get createdAt;
@BuiltValueField(wireName: 'updated_at')
String? get updatedAt;
@BuiltValueField(wireName: 'width')
int? get width;
@BuiltValueField(wireName: 'height')
int? get height;
@BuiltValueField(wireName: 'color')
String? get color;
@BuiltValueField(wireName: 'downloads')
int? get downloads;
@BuiltValueField(wireName: 'likes')
int? get likes;
@BuiltValueField(wireName: 'liked_by_user')
bool? get likedByUser;
@BuiltValueField(wireName: 'description')
String? get description;
@BuiltValueField(wireName: 'exif')
Exif? get exif;
@BuiltValueField(wireName: 'location')
Location? get location;
@BuiltValueField(wireName: 'tags')
BuiltList<Tags>? get tags;
@BuiltValueField(wireName: 'current_user_collections')
BuiltList<CurrentUserCollections>? get currentUserCollections;
@BuiltValueField(wireName: 'urls')
Urls? get urls;
@BuiltValueField(wireName: 'links')
Links? get links;
@BuiltValueField(wireName: 'user')
User? get user;
String toJson() {
return json.encode(serializers.serializeWith(Photo.serializer, this));
}
static Photo? fromJson(String jsonString) {
return serializers.deserializeWith(
Photo.serializer, json.decode(jsonString));
}
static Serializer<Photo> get serializer => _$photoSerializer;
}

View File

@@ -0,0 +1,553 @@
// 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)),
];
Object? value;
value = object.createdAt;
if (value != null) {
result
..add('created_at')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.updatedAt;
if (value != null) {
result
..add('updated_at')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.width;
if (value != null) {
result
..add('width')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.height;
if (value != null) {
result
..add('height')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.color;
if (value != null) {
result
..add('color')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.downloads;
if (value != null) {
result
..add('downloads')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.likes;
if (value != null) {
result
..add('likes')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.likedByUser;
if (value != null) {
result
..add('liked_by_user')
..add(
serializers.serialize(value, specifiedType: const FullType(bool)));
}
value = object.description;
if (value != null) {
result
..add('description')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.exif;
if (value != null) {
result
..add('exif')
..add(
serializers.serialize(value, specifiedType: const FullType(Exif)));
}
value = object.location;
if (value != null) {
result
..add('location')
..add(serializers.serialize(value,
specifiedType: const FullType(Location)));
}
value = object.tags;
if (value != null) {
result
..add('tags')
..add(serializers.serialize(value,
specifiedType:
const FullType(BuiltList, const [const FullType(Tags)])));
}
value = object.currentUserCollections;
if (value != null) {
result
..add('current_user_collections')
..add(serializers.serialize(value,
specifiedType: const FullType(
BuiltList, const [const FullType(CurrentUserCollections)])));
}
value = object.urls;
if (value != null) {
result
..add('urls')
..add(
serializers.serialize(value, specifiedType: const FullType(Urls)));
}
value = object.links;
if (value != null) {
result
..add('links')
..add(
serializers.serialize(value, specifiedType: const FullType(Links)));
}
value = object.user;
if (value != null) {
result
..add('user')
..add(
serializers.serialize(value, 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 Object? 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<Object?>);
break;
case 'current_user_collections':
result.currentUserCollections.replace(serializers.deserialize(value,
specifiedType: const FullType(BuiltList, const [
const FullType(CurrentUserCollections)
]))! as BuiltList<Object?>);
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._(
{required 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._() {
BuiltValueNullFieldError.checkNotNull(id, '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 {
final $v = _$v;
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) {
ArgumentError.checkNotNull(other, '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: BuiltValueNullFieldError.checkNotNull(id, 'Photo', '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 (_) {
late 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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

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

View File

@@ -0,0 +1,152 @@
// 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 Object? 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._({required this.latitude, required this.longitude}) : super._() {
BuiltValueNullFieldError.checkNotNull(latitude, 'Position', 'latitude');
BuiltValueNullFieldError.checkNotNull(longitude, '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 {
final $v = _$v;
if ($v != null) {
_latitude = $v.latitude;
_longitude = $v.longitude;
_$v = null;
}
return this;
}
@override
void replace(Position other) {
ArgumentError.checkNotNull(other, '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: BuiltValueNullFieldError.checkNotNull(
latitude, 'Position', 'latitude'),
longitude: BuiltValueNullFieldError.checkNotNull(
longitude, 'Position', '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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,45 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:built_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._();
@BuiltValueField(wireName: 'total')
int? get total;
@BuiltValueField(wireName: 'total_pages')
int? get totalPages;
@BuiltValueField(wireName: 'results')
BuiltList<Photo> get results;
String toJson() {
return json.encode(
serializers.serializeWith(SearchPhotosResponse.serializer, this));
}
static SearchPhotosResponse? fromJson(String jsonString) {
return serializers.deserializeWith(
SearchPhotosResponse.serializer, json.decode(jsonString));
}
static Serializer<SearchPhotosResponse> get serializer =>
_$searchPhotosResponseSerializer;
}

View File

@@ -0,0 +1,201 @@
// 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)])),
];
Object? value;
value = object.total;
if (value != null) {
result
..add('total')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.totalPages;
if (value != null) {
result
..add('total_pages')
..add(serializers.serialize(value, 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 Object? 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<Object?>);
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, required this.results})
: super._() {
BuiltValueNullFieldError.checkNotNull(
results, '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 {
final $v = _$v;
if ($v != null) {
_total = $v.total;
_totalPages = $v.totalPages;
_results = $v.results.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(SearchPhotosResponse other) {
ArgumentError.checkNotNull(other, '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 (_) {
late 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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

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

View File

@@ -0,0 +1,131 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tags.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<Tags> _$tagsSerializer = new _$TagsSerializer();
class _$TagsSerializer implements StructuredSerializer<Tags> {
@override
final Iterable<Type> types = const [Tags, _$Tags];
@override
final String wireName = 'Tags';
@override
Iterable<Object?> serialize(Serializers serializers, Tags object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object?>[
'title',
serializers.serialize(object.title,
specifiedType: const FullType(String)),
];
return result;
}
@override
Tags deserialize(Serializers serializers, Iterable<Object?> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new TagsBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final Object? 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._({required this.title}) : super._() {
BuiltValueNullFieldError.checkNotNull(title, '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 {
final $v = _$v;
if ($v != null) {
_title = $v.title;
_$v = null;
}
return this;
}
@override
void replace(Tags other) {
ArgumentError.checkNotNull(other, '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:
BuiltValueNullFieldError.checkNotNull(title, 'Tags', '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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,118 @@
// 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 '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,
}) : _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.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.fuse(utf8).decode(response.bodyBytes);
} 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(Uri.parse(photo.urls!.full!), headers: {
'Accept-Version': 'v1',
'Authorization': 'Client-ID $_accessKey',
});
_log.info('GET ${photo.links!.downloadLocation}');
http.get(Uri.parse(photo.links!.downloadLocation!), headers: {
'Accept-Version': 'v1',
'Authorization': 'Client-ID $_accessKey',
});
return futureBytes;
}
}
enum SearchPhotosOrientation {
landscape,
portrait,
squarish,
}
class UnsplashException implements Exception {
UnsplashException([this.message]);
final String? message;
@override
String toString() {
if (message == null) {
return 'UnsplashException';
}
return 'UnsplashException: $message';
}
}

View File

@@ -0,0 +1,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.
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._();
@BuiltValueField(wireName: 'raw')
String? get raw;
@BuiltValueField(wireName: 'full')
String? get full;
@BuiltValueField(wireName: 'regular')
String? get regular;
@BuiltValueField(wireName: 'small')
String? get small;
@BuiltValueField(wireName: 'thumb')
String? get thumb;
String toJson() {
return json.encode(serializers.serializeWith(Urls.serializer, this));
}
static Urls? fromJson(String jsonString) {
return serializers.deserializeWith(
Urls.serializer, json.decode(jsonString));
}
static Serializer<Urls> get serializer => _$urlsSerializer;
}

View File

@@ -0,0 +1,217 @@
// 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?>[];
Object? value;
value = object.raw;
if (value != null) {
result
..add('raw')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.full;
if (value != null) {
result
..add('full')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.regular;
if (value != null) {
result
..add('regular')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.small;
if (value != null) {
result
..add('small')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.thumb;
if (value != null) {
result
..add('thumb')
..add(serializers.serialize(value,
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 Object? 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 {
final $v = _$v;
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) {
ArgumentError.checkNotNull(other, '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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,63 @@
// 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;
@BuiltValueField(wireName: 'updated_at')
String? get updatedAt;
@BuiltValueField(wireName: 'username')
String get username;
@BuiltValueField(wireName: 'name')
String get name;
@BuiltValueField(wireName: 'portfolio_url')
String? get portfolioUrl;
@BuiltValueField(wireName: 'bio')
String? get bio;
@BuiltValueField(wireName: 'location')
String? get location;
@BuiltValueField(wireName: 'total_likes')
int? get totalLikes;
@BuiltValueField(wireName: 'total_photos')
int? get totalPhotos;
@BuiltValueField(wireName: 'total_collections')
int? get totalCollections;
@BuiltValueField(wireName: 'links')
Links? get links;
String toJson() {
return json.encode(serializers.serializeWith(User.serializer, this));
}
static User? fromJson(String jsonString) {
return serializers.deserializeWith(
User.serializer, json.decode(jsonString));
}
static Serializer<User> get serializer => _$userSerializer;
}

View File

@@ -0,0 +1,377 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<User> _$userSerializer = new _$UserSerializer();
class _$UserSerializer implements StructuredSerializer<User> {
@override
final Iterable<Type> types = const [User, _$User];
@override
final String wireName = 'User';
@override
Iterable<Object?> serialize(Serializers serializers, User object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object?>[
'id',
serializers.serialize(object.id, specifiedType: const FullType(String)),
'username',
serializers.serialize(object.username,
specifiedType: const FullType(String)),
'name',
serializers.serialize(object.name, specifiedType: const FullType(String)),
];
Object? value;
value = object.updatedAt;
if (value != null) {
result
..add('updated_at')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.portfolioUrl;
if (value != null) {
result
..add('portfolio_url')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.bio;
if (value != null) {
result
..add('bio')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.location;
if (value != null) {
result
..add('location')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
value = object.totalLikes;
if (value != null) {
result
..add('total_likes')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.totalPhotos;
if (value != null) {
result
..add('total_photos')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.totalCollections;
if (value != null) {
result
..add('total_collections')
..add(serializers.serialize(value, specifiedType: const FullType(int)));
}
value = object.links;
if (value != null) {
result
..add('links')
..add(
serializers.serialize(value, 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 Object? 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._(
{required this.id,
this.updatedAt,
required this.username,
required this.name,
this.portfolioUrl,
this.bio,
this.location,
this.totalLikes,
this.totalPhotos,
this.totalCollections,
this.links})
: super._() {
BuiltValueNullFieldError.checkNotNull(id, 'User', 'id');
BuiltValueNullFieldError.checkNotNull(username, 'User', 'username');
BuiltValueNullFieldError.checkNotNull(name, '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 {
final $v = _$v;
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) {
ArgumentError.checkNotNull(other, '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: BuiltValueNullFieldError.checkNotNull(id, 'User', 'id'),
updatedAt: updatedAt,
username: BuiltValueNullFieldError.checkNotNull(
username, 'User', 'username'),
name: BuiltValueNullFieldError.checkNotNull(name, 'User', 'name'),
portfolioUrl: portfolioUrl,
bio: bio,
location: location,
totalLikes: totalLikes,
totalPhotos: totalPhotos,
totalCollections: totalCollections,
links: _links?.build());
} catch (_) {
late 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,deprecated_member_use_from_same_package,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new

View File

@@ -0,0 +1,113 @@
// 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:transparent_image/transparent_image.dart';
import 'package:url_launcher/link.dart';
import '../../unsplash_access_key.dart';
import '../unsplash/photo.dart';
final _unsplashHomepage = Uri.parse(
'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,
Key? key,
}) : super(key: key);
final Photo photo;
final PhotoDetailsPhotoSaveCallback onPhotoSave;
@override
_PhotoDetailsState createState() => _PhotoDetailsState();
}
class _PhotoDetailsState extends State<PhotoDetails> {
Widget _buildPhotoAttribution(BuildContext context) {
return Row(
children: [
const Text('Photo by '),
Link(
uri: Uri.parse(
'https://unsplash.com/@${widget.photo.user!.username}?utm_source=$unsplashAppName&utm_medium=referral'),
builder: (context, followLink) => TextButton(
onPressed: followLink,
child: Text(widget.photo.user!.name),
),
),
const Text(' on '),
Link(
uri: _unsplashHomepage,
builder: (context, followLink) => TextButton(
onPressed: followLink,
child: const Text('Unsplash'),
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scrollbar(
child: SingleChildScrollView(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 16),
Card(
shape: ContinuousRectangleBorder(
side: const BorderSide(color: Colors.black12),
borderRadius: BorderRadius.circular(4),
),
child: AnimatedSize(
duration: const Duration(milliseconds: 750),
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 40),
child: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 400,
minHeight: 400,
),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
imageSemanticLabel: widget.photo.description,
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(
tooltip: 'Download',
visualDensity: VisualDensity.compact,
icon: const Icon(Icons.cloud_download),
onPressed: () => widget.onPhotoSave(widget.photo),
),
],
),
),
const SizedBox(height: 48),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,70 @@
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
typedef PhotoSearchDialogCallback = void Function(String searchQuery);
class PhotoSearchDialog extends StatefulWidget {
const PhotoSearchDialog({required this.callback, Key? key}) : super(key: key);
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: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('CANCEL'),
),
TextButton(
onPressed: _searchEnabled
? () {
widget.callback(_controller.text);
Navigator.of(context).pop();
}
: null,
child: const Text('SEARCH'),
),
],
);
}

View File

@@ -0,0 +1,74 @@
// 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/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart' as url_launcher;
class PolicyDialog extends StatelessWidget {
const PolicyDialog({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Terms & Conditions'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
textAlign: TextAlign.left,
text: TextSpan(
text: '',
style: const TextStyle(color: Colors.black, fontSize: 18),
children: [
TextSpan(
text: 'https://policies.google.com/terms',
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.lightBlue),
recognizer: TapGestureRecognizer()
..onTap = () async {
const url = 'https://policies.google.com/terms';
if (await url_launcher.canLaunch(url)) {
await url_launcher.launch(url);
}
},
)
],
),
),
RichText(
textAlign: TextAlign.left,
text: TextSpan(
text: '',
style: const TextStyle(color: Colors.black, fontSize: 18),
children: [
TextSpan(
text: 'https://unsplash.com/terms',
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.lightBlue),
recognizer: TapGestureRecognizer()
..onTap = () async {
const url = 'https://unsplash.com/terms';
if (await url_launcher.canLaunch(url)) {
await url_launcher.launch(url);
}
},
)
],
),
),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('CLOSE'),
),
],
);
}
}

View File

@@ -0,0 +1,190 @@
// 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,
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> {
late 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.
var firstSize = axisSize * firstFraction;
var secondSize = axisSize * secondFraction;
// Clamp the sizes to be sure there is enough space for the dividers.
firstSize = firstSize.clamp(halfDivider, axisSize - halfDivider);
secondSize = secondSize.clamp(halfDivider, axisSize - halfDivider);
// 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);
});
}
// TODO(https://github.com/flutter/flutter/issues/43747): use an icon.
// The material icon for a drag handle is not currently available.
// For now, draw an indicator that is 3 lines running in the direction
// of the main axis, like a hamburger menu.
// TODO(https://github.com/flutter/devtools/issues/1265): update mouse
// to indicate that this is resizable.
final dragIndicator = Flex(
direction: isHorizontal ? Axis.vertical : Axis.horizontal,
mainAxisSize: MainAxisSize.min,
children: [
for (var i = 0; i < min(crossAxisSize / 6.0, 3).floor(); i++)
Padding(
padding: EdgeInsets.symmetric(
vertical: isHorizontal ? 2.0 : 0.0,
horizontal: isHorizontal ? 0.0 : 2.0,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).dividerColor,
borderRadius: BorderRadius.circular(Split.dividerMainAxisSize),
),
child: SizedBox(
height: isHorizontal ? 2.0 : Split.dividerMainAxisSize - 2.0,
width: isHorizontal ? Split.dividerMainAxisSize - 2.0 : 2.0,
),
),
),
],
);
final children = [
SizedBox(
width: isHorizontal ? firstSize : width,
height: isHorizontal ? height : firstSize,
child: widget.firstChild,
),
GestureDetector(
key: widget.dividerKey,
behavior: HitTestBehavior.translucent,
onHorizontalDragUpdate: isHorizontal ? updateSpacing : null,
onVerticalDragUpdate: isHorizontal ? null : updateSpacing,
// DartStartBehavior.down is needed to keep the mouse pointer stuck to
// the drag bar. There still appears to be a few frame lag before the
// drag action triggers which is't ideal but isn't a launch blocker.
dragStartBehavior: DragStartBehavior.down,
child: SizedBox(
width: isHorizontal ? Split.dividerMainAxisSize : width,
height: isHorizontal ? height : Split.dividerMainAxisSize,
child: Center(
child: dragIndicator,
),
),
),
SizedBox(
width: isHorizontal ? secondSize : width,
height: isHorizontal ? height : secondSize,
child: widget.secondChild,
),
];
return Flex(direction: widget.axis, children: children);
}
}

View File

@@ -0,0 +1,107 @@
// Copyright 2022 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/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../unsplash_access_key.dart';
final _unsplashHomepage =
'https://unsplash.com/?utm_source=${Uri.encodeFull(unsplashAppName)}&utm_medium=referral';
final _unsplashPrivacyPolicy =
'https://unsplash.com/privacy?utm_source=${Uri.encodeFull(unsplashAppName)}&utm_medium=referral';
class UnsplashNotice extends StatefulWidget {
const UnsplashNotice({Key? key, required this.child}) : super(key: key);
final Widget child;
@override
State<UnsplashNotice> createState() => _UnsplashNoticeState();
}
class _UnsplashNoticeState extends State<UnsplashNotice> {
bool noticeAccepted = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
showDialog<void>(
barrierDismissible: false,
context: context,
builder: (context) {
return _UnsplashDialog(accepted: () {
setState(() {
noticeAccepted = true;
});
});
});
});
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
class _UnsplashDialog extends StatelessWidget {
const _UnsplashDialog({Key? key, required this.accepted}) : super(key: key);
final Function accepted;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Unsplash Notice'),
content: RichText(
text: TextSpan(
text: 'This is a sample desktop application provided by Google'
' that enables you to search ',
style: const TextStyle(color: Colors.grey),
children: [
TextSpan(
text: 'Unsplash',
recognizer: TapGestureRecognizer()
..onTap = () async {
if (!await launch(_unsplashHomepage)) {
throw 'Could not launch $_unsplashHomepage';
}
},
style: const TextStyle(color: Colors.blue),
),
const TextSpan(
text: ' for photographs that interest you. When you search'
' for and interact with photos, Unsplash will collect'
' information about you and your use of the Unsplash'
' services. Learn more about ',
style: TextStyle(color: Colors.grey),
),
TextSpan(
text: 'how Unsplash collects and uses data',
recognizer: TapGestureRecognizer()
..onTap = () async {
if (!await launch(_unsplashPrivacyPolicy)) {
throw 'Could not launch $_unsplashPrivacyPolicy';
}
},
style: const TextStyle(color: Colors.blue),
),
const TextSpan(
text: '.',
style: TextStyle(color: Colors.grey),
),
]),
),
actions: [
TextButton(
child: const Text('GOT IT'),
onPressed: () {
accepted();
Navigator.pop(context);
})
],
);
}
}

View File

@@ -0,0 +1,105 @@
// Copyright 2022 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:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:flutter_simple_treeview/flutter_simple_treeview.dart';
import 'package:provider/provider.dart';
import '../model/photo_search_model.dart';
import '../unsplash/photo.dart';
import '../widgets/photo_details.dart';
import '../widgets/split.dart';
class UnsplashSearchContent extends StatefulWidget {
const UnsplashSearchContent({Key? key}) : super(key: key);
@override
State<UnsplashSearchContent> createState() => _UnsplashSearchContentState();
}
class _UnsplashSearchContentState extends State<UnsplashSearchContent> {
final _treeViewScrollController = ScrollController();
@override
Widget build(BuildContext context) {
final photoSearchModel = Provider.of<PhotoSearchModel>(context);
return Split(
axis: Axis.horizontal,
initialFirstFraction: 0.4,
firstChild: Scrollbar(
controller: _treeViewScrollController,
child: SingleChildScrollView(
controller: _treeViewScrollController,
child: TreeView(
nodes: photoSearchModel.entries.map(_buildSearchEntry).toList(),
indent: 0,
),
),
),
secondChild: Center(
child: photoSearchModel.selectedPhoto != null
? PhotoDetails(
photo: photoSearchModel.selectedPhoto!,
onPhotoSave: (photo) async {
final path = await getSavePath(
suggestedName: '${photo.id}.jpg',
acceptedTypeGroups: [
XTypeGroup(
label: 'JPG',
extensions: ['jpg'],
mimeTypes: ['image/jpeg'],
),
],
);
if (path != null) {
final fileData =
await photoSearchModel.download(photo: photo);
final photoFile =
XFile.fromData(fileData, mimeType: 'image/jpeg');
await photoFile.saveTo(path);
}
},
)
: Container(),
),
);
}
TreeNode _buildSearchEntry(SearchEntry searchEntry) {
void selectPhoto(Photo photo) {
searchEntry.model.selectedPhoto = photo;
}
String labelForPhoto(Photo photo) => 'Photo by ${photo.user!.name}';
return TreeNode(
content: Expanded(
child: Text(searchEntry.query),
),
children: searchEntry.photos
.map<TreeNode>(
(photo) => TreeNode(
content: Expanded(
child: Semantics(
button: true,
onTap: () => selectPhoto(photo),
label: labelForPhoto(photo),
excludeSemantics: true,
child: InkWell(
onTap: () => selectPhoto(photo),
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(labelForPhoto(photo)),
),
),
),
),
),
)
.toList(),
);
}
}