mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Dart 3.9 / Flutter 3.35 [first LLM release] (#2714)
I got carried away with Gemini and basically rewrote CI and the release process for the new LLM reality. This work was largely completed by Gemini. - Bump all SDK versions to the current beta (3.9.0-0) - Run `flutter channel beta` - Wrote `ci_script.dart` to replace the bash scripts - Converted repository to pub workspace #2499 - Added llm.md and release.md - Added redirect for deprecated Samples Index ## Pre-launch Checklist - [x] I read the [Flutter Style Guide] _recently_, and have followed its advice. - [x] I signed the [CLA]. - [x] I read the [Contributors Guide]. - [x] I have added sample code updates to the [changelog]. - [x] I updated/added relevant documentation (doc comments with `///`).
This commit is contained in:
@@ -24,7 +24,9 @@ void main() {
|
||||
Logger.root.level = Level.ALL;
|
||||
Logger.root.onRecord.listen((rec) {
|
||||
// ignore: avoid_print
|
||||
print('${rec.loggerName} ${rec.level.name}: ${rec.time}: ${rec.message}');
|
||||
print(
|
||||
'${rec.loggerName} ${rec.level.name}: ${rec.time}: ${rec.message}',
|
||||
);
|
||||
});
|
||||
|
||||
if (unsplashAccessKey.isEmpty) {
|
||||
@@ -39,8 +41,8 @@ void main() {
|
||||
|
||||
runApp(
|
||||
ChangeNotifierProvider<PhotoSearchModel>(
|
||||
create:
|
||||
(context) => PhotoSearchModel(Unsplash(accessKey: unsplashAccessKey)),
|
||||
create: (context) =>
|
||||
PhotoSearchModel(Unsplash(accessKey: unsplashAccessKey)),
|
||||
child: const UnsplashSearchApp(),
|
||||
),
|
||||
);
|
||||
@@ -50,7 +52,8 @@ const double windowWidth = 1024;
|
||||
const double windowHeight = 800;
|
||||
|
||||
void setupWindow() {
|
||||
if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
|
||||
if (!kIsWeb &&
|
||||
(Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
setWindowMinSize(const Size(windowWidth, windowHeight));
|
||||
}
|
||||
@@ -85,9 +88,9 @@ class UnsplashHomePage extends StatelessWidget {
|
||||
onSelected: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder:
|
||||
(context) =>
|
||||
PhotoSearchDialog(callback: photoSearchModel.addSearch),
|
||||
builder: (context) => PhotoSearchDialog(
|
||||
callback: photoSearchModel.addSearch,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -119,20 +122,17 @@ class UnsplashHomePage extends StatelessWidget {
|
||||
return UnsplashNotice(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(title: Text(title)),
|
||||
body:
|
||||
photoSearchModel.entries.isNotEmpty
|
||||
? const UnsplashSearchContent()
|
||||
: const Center(
|
||||
child: Text('Search for Photos using the Fab button'),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed:
|
||||
() => showDialog<void>(
|
||||
context: context,
|
||||
builder:
|
||||
(context) =>
|
||||
PhotoSearchDialog(callback: photoSearchModel.addSearch),
|
||||
body: photoSearchModel.entries.isNotEmpty
|
||||
? const UnsplashSearchContent()
|
||||
: const Center(
|
||||
child: Text('Search for Photos using the Fab button'),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
PhotoSearchDialog(callback: photoSearchModel.addSearch),
|
||||
),
|
||||
tooltip: 'Search for a photo',
|
||||
child: const Icon(Icons.search),
|
||||
),
|
||||
|
||||
@@ -45,5 +45,6 @@ class PhotoSearchModel extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<Uint8List> download({required Photo photo}) => _client.download(photo);
|
||||
Future<Uint8List> download({required Photo photo}) =>
|
||||
_client.download(photo);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ class _$SearchSerializer implements StructuredSerializer<Search> {
|
||||
'results',
|
||||
serializers.serialize(
|
||||
object.results,
|
||||
specifiedType: const FullType(BuiltList, const [const FullType(Photo)]),
|
||||
specifiedType: const FullType(BuiltList, const [
|
||||
const FullType(Photo),
|
||||
]),
|
||||
),
|
||||
];
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ abstract class ApiError implements Built<ApiError, ApiErrorBuilder> {
|
||||
BuiltList<String>? get errors;
|
||||
|
||||
String toJson() {
|
||||
return json.encode(serializers.serializeWith(ApiError.serializer, this));
|
||||
return json.encode(
|
||||
serializers.serializeWith(ApiError.serializer, this),
|
||||
);
|
||||
}
|
||||
|
||||
static ApiError? fromJson(String jsonString) {
|
||||
|
||||
@@ -106,8 +106,9 @@ class _$ApiError extends ApiError {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (newBuiltValueToStringHelper(r'ApiError')
|
||||
..add('errors', errors)).toString();
|
||||
return (newBuiltValueToStringHelper(
|
||||
r'ApiError',
|
||||
)..add('errors', errors)).toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,10 @@ class _$CurrentUserCollectionsSerializer
|
||||
result
|
||||
..add('title')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.publishedAt;
|
||||
@@ -47,7 +50,10 @@ class _$CurrentUserCollectionsSerializer
|
||||
result
|
||||
..add('published_at')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.updatedAt;
|
||||
@@ -55,7 +61,10 @@ class _$CurrentUserCollectionsSerializer
|
||||
result
|
||||
..add('updated_at')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
@@ -134,7 +143,11 @@ class _$CurrentUserCollections extends CurrentUserCollections {
|
||||
this.publishedAt,
|
||||
this.updatedAt,
|
||||
}) : super._() {
|
||||
BuiltValueNullFieldError.checkNotNull(id, r'CurrentUserCollections', 'id');
|
||||
BuiltValueNullFieldError.checkNotNull(
|
||||
id,
|
||||
r'CurrentUserCollections',
|
||||
'id',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -31,7 +31,10 @@ class _$ExifSerializer implements StructuredSerializer<Exif> {
|
||||
result
|
||||
..add('make')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.model;
|
||||
@@ -39,7 +42,10 @@ class _$ExifSerializer implements StructuredSerializer<Exif> {
|
||||
result
|
||||
..add('model')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.exposureTime;
|
||||
@@ -47,7 +53,10 @@ class _$ExifSerializer implements StructuredSerializer<Exif> {
|
||||
result
|
||||
..add('exposure_time')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.aperture;
|
||||
@@ -55,7 +64,10 @@ class _$ExifSerializer implements StructuredSerializer<Exif> {
|
||||
result
|
||||
..add('aperture')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.focalLength;
|
||||
@@ -63,14 +75,19 @@ class _$ExifSerializer implements StructuredSerializer<Exif> {
|
||||
result
|
||||
..add('focal_length')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.iso;
|
||||
if (value != null) {
|
||||
result
|
||||
..add('iso')
|
||||
..add(serializers.serialize(value, specifiedType: const FullType(int)));
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(int)),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -131,7 +148,10 @@ class _$ExifSerializer implements StructuredSerializer<Exif> {
|
||||
break;
|
||||
case 'iso':
|
||||
result.iso =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
}
|
||||
@@ -225,7 +245,8 @@ class ExifBuilder implements Builder<Exif, ExifBuilder> {
|
||||
|
||||
String? _exposureTime;
|
||||
String? get exposureTime => _$this._exposureTime;
|
||||
set exposureTime(String? exposureTime) => _$this._exposureTime = exposureTime;
|
||||
set exposureTime(String? exposureTime) =>
|
||||
_$this._exposureTime = exposureTime;
|
||||
|
||||
String? _aperture;
|
||||
String? get aperture => _$this._aperture;
|
||||
|
||||
@@ -31,7 +31,10 @@ class _$LinksSerializer implements StructuredSerializer<Links> {
|
||||
result
|
||||
..add('self')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.html;
|
||||
@@ -39,7 +42,10 @@ class _$LinksSerializer implements StructuredSerializer<Links> {
|
||||
result
|
||||
..add('html')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.download;
|
||||
@@ -47,7 +53,10 @@ class _$LinksSerializer implements StructuredSerializer<Links> {
|
||||
result
|
||||
..add('download')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.downloadLocation;
|
||||
@@ -55,7 +64,10 @@ class _$LinksSerializer implements StructuredSerializer<Links> {
|
||||
result
|
||||
..add('download_location')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -27,7 +27,9 @@ abstract class Location implements Built<Location, LocationBuilder> {
|
||||
Position? get position;
|
||||
|
||||
String toJson() {
|
||||
return json.encode(serializers.serializeWith(Location.serializer, this));
|
||||
return json.encode(
|
||||
serializers.serializeWith(Location.serializer, this),
|
||||
);
|
||||
}
|
||||
|
||||
static Location? fromJson(String jsonString) {
|
||||
|
||||
@@ -31,7 +31,10 @@ class _$LocationSerializer implements StructuredSerializer<Location> {
|
||||
result
|
||||
..add('city')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.country;
|
||||
@@ -39,7 +42,10 @@ class _$LocationSerializer implements StructuredSerializer<Location> {
|
||||
result
|
||||
..add('country')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.position;
|
||||
@@ -47,7 +53,10 @@ class _$LocationSerializer implements StructuredSerializer<Location> {
|
||||
result
|
||||
..add('position')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(Position)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(Position),
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -26,7 +26,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
}) {
|
||||
final result = <Object?>[
|
||||
'id',
|
||||
serializers.serialize(object.id, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
object.id,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
];
|
||||
Object? value;
|
||||
value = object.createdAt;
|
||||
@@ -34,7 +37,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('created_at')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.updatedAt;
|
||||
@@ -42,47 +48,64 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('updated_at')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.width;
|
||||
if (value != null) {
|
||||
result
|
||||
..add('width')
|
||||
..add(serializers.serialize(value, specifiedType: const FullType(int)));
|
||||
..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)));
|
||||
..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)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.downloads;
|
||||
if (value != null) {
|
||||
result
|
||||
..add('downloads')
|
||||
..add(serializers.serialize(value, specifiedType: const FullType(int)));
|
||||
..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)));
|
||||
..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)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(bool),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.description;
|
||||
@@ -90,7 +113,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('description')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.exif;
|
||||
@@ -98,7 +124,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('exif')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(Exif)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(Exif),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.location;
|
||||
@@ -106,7 +135,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('location')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(Location)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(Location),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.tags;
|
||||
@@ -140,7 +172,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('urls')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(Urls)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(Urls),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.links;
|
||||
@@ -148,7 +183,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('links')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(Links)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(Links),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.user;
|
||||
@@ -156,7 +194,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
result
|
||||
..add('user')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(User)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(User),
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
@@ -202,12 +243,18 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
break;
|
||||
case 'width':
|
||||
result.width =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'height':
|
||||
result.height =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'color':
|
||||
@@ -220,12 +267,18 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
break;
|
||||
case 'downloads':
|
||||
result.downloads =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'likes':
|
||||
result.likes =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'liked_by_user':
|
||||
@@ -246,7 +299,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
break;
|
||||
case 'exif':
|
||||
result.exif.replace(
|
||||
serializers.deserialize(value, specifiedType: const FullType(Exif))!
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(Exif),
|
||||
)!
|
||||
as Exif,
|
||||
);
|
||||
break;
|
||||
@@ -283,7 +339,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
break;
|
||||
case 'urls':
|
||||
result.urls.replace(
|
||||
serializers.deserialize(value, specifiedType: const FullType(Urls))!
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(Urls),
|
||||
)!
|
||||
as Urls,
|
||||
);
|
||||
break;
|
||||
@@ -298,7 +357,10 @@ class _$PhotoSerializer implements StructuredSerializer<Photo> {
|
||||
break;
|
||||
case 'user':
|
||||
result.user.replace(
|
||||
serializers.deserialize(value, specifiedType: const FullType(User))!
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(User),
|
||||
)!
|
||||
as User,
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -23,7 +23,9 @@ abstract class Position implements Built<Position, PositionBuilder> {
|
||||
double get longitude;
|
||||
|
||||
String toJson() {
|
||||
return json.encode(serializers.serializeWith(Position.serializer, this));
|
||||
return json.encode(
|
||||
serializers.serializeWith(Position.serializer, this),
|
||||
);
|
||||
}
|
||||
|
||||
static Position? fromJson(String jsonString) {
|
||||
|
||||
@@ -87,8 +87,16 @@ class _$Position extends Position {
|
||||
(new PositionBuilder()..update(updates))._build();
|
||||
|
||||
_$Position._({required this.latitude, required this.longitude}) : super._() {
|
||||
BuiltValueNullFieldError.checkNotNull(latitude, r'Position', 'latitude');
|
||||
BuiltValueNullFieldError.checkNotNull(longitude, r'Position', 'longitude');
|
||||
BuiltValueNullFieldError.checkNotNull(
|
||||
latitude,
|
||||
r'Position',
|
||||
'latitude',
|
||||
);
|
||||
BuiltValueNullFieldError.checkNotNull(
|
||||
longitude,
|
||||
r'Position',
|
||||
'longitude',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -33,7 +33,9 @@ class _$SearchPhotosResponseSerializer
|
||||
'results',
|
||||
serializers.serialize(
|
||||
object.results,
|
||||
specifiedType: const FullType(BuiltList, const [const FullType(Photo)]),
|
||||
specifiedType: const FullType(BuiltList, const [
|
||||
const FullType(Photo),
|
||||
]),
|
||||
),
|
||||
];
|
||||
Object? value;
|
||||
@@ -41,13 +43,17 @@ class _$SearchPhotosResponseSerializer
|
||||
if (value != null) {
|
||||
result
|
||||
..add('total')
|
||||
..add(serializers.serialize(value, specifiedType: const FullType(int)));
|
||||
..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)));
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(int)),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -68,12 +74,18 @@ class _$SearchPhotosResponseSerializer
|
||||
switch (key) {
|
||||
case 'total':
|
||||
result.total =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'total_pages':
|
||||
result.totalPages =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'results':
|
||||
@@ -106,8 +118,11 @@ class _$SearchPhotosResponse extends SearchPhotosResponse {
|
||||
void Function(SearchPhotosResponseBuilder)? updates,
|
||||
]) => (new SearchPhotosResponseBuilder()..update(updates))._build();
|
||||
|
||||
_$SearchPhotosResponse._({this.total, this.totalPages, required this.results})
|
||||
: super._() {
|
||||
_$SearchPhotosResponse._({
|
||||
this.total,
|
||||
this.totalPages,
|
||||
required this.results,
|
||||
}) : super._() {
|
||||
BuiltValueNullFieldError.checkNotNull(
|
||||
results,
|
||||
r'SearchPhotosResponse',
|
||||
|
||||
@@ -98,8 +98,9 @@ class _$Tags extends Tags {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (newBuiltValueToStringHelper(r'Tags')
|
||||
..add('title', title)).toString();
|
||||
return (newBuiltValueToStringHelper(
|
||||
r'Tags',
|
||||
)..add('title', title)).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +140,11 @@ class TagsBuilder implements Builder<Tags, TagsBuilder> {
|
||||
final _$result =
|
||||
_$v ??
|
||||
new _$Tags._(
|
||||
title: BuiltValueNullFieldError.checkNotNull(title, r'Tags', 'title'),
|
||||
title: BuiltValueNullFieldError.checkNotNull(
|
||||
title,
|
||||
r'Tags',
|
||||
'title',
|
||||
),
|
||||
);
|
||||
replace(_$result);
|
||||
return _$result;
|
||||
|
||||
@@ -31,7 +31,10 @@ class _$UrlsSerializer implements StructuredSerializer<Urls> {
|
||||
result
|
||||
..add('raw')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.full;
|
||||
@@ -39,7 +42,10 @@ class _$UrlsSerializer implements StructuredSerializer<Urls> {
|
||||
result
|
||||
..add('full')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.regular;
|
||||
@@ -47,7 +53,10 @@ class _$UrlsSerializer implements StructuredSerializer<Urls> {
|
||||
result
|
||||
..add('regular')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.small;
|
||||
@@ -55,7 +64,10 @@ class _$UrlsSerializer implements StructuredSerializer<Urls> {
|
||||
result
|
||||
..add('small')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.thumb;
|
||||
@@ -63,7 +75,10 @@ class _$UrlsSerializer implements StructuredSerializer<Urls> {
|
||||
result
|
||||
..add('thumb')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -26,14 +26,20 @@ class _$UserSerializer implements StructuredSerializer<User> {
|
||||
}) {
|
||||
final result = <Object?>[
|
||||
'id',
|
||||
serializers.serialize(object.id, specifiedType: const FullType(String)),
|
||||
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)),
|
||||
serializers.serialize(
|
||||
object.name,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
];
|
||||
Object? value;
|
||||
value = object.updatedAt;
|
||||
@@ -41,7 +47,10 @@ class _$UserSerializer implements StructuredSerializer<User> {
|
||||
result
|
||||
..add('updated_at')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.portfolioUrl;
|
||||
@@ -49,7 +58,10 @@ class _$UserSerializer implements StructuredSerializer<User> {
|
||||
result
|
||||
..add('portfolio_url')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.bio;
|
||||
@@ -57,7 +69,10 @@ class _$UserSerializer implements StructuredSerializer<User> {
|
||||
result
|
||||
..add('bio')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(String),
|
||||
),
|
||||
);
|
||||
}
|
||||
value = object.location;
|
||||
@@ -65,33 +80,45 @@ class _$UserSerializer implements StructuredSerializer<User> {
|
||||
result
|
||||
..add('location')
|
||||
..add(
|
||||
serializers.serialize(value, specifiedType: const FullType(String)),
|
||||
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)));
|
||||
..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)));
|
||||
..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)));
|
||||
..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)),
|
||||
serializers.serialize(
|
||||
value,
|
||||
specifiedType: const FullType(Links),
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
@@ -169,17 +196,26 @@ class _$UserSerializer implements StructuredSerializer<User> {
|
||||
break;
|
||||
case 'total_likes':
|
||||
result.totalLikes =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'total_photos':
|
||||
result.totalPhotos =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'total_collections':
|
||||
result.totalCollections =
|
||||
serializers.deserialize(value, specifiedType: const FullType(int))
|
||||
serializers.deserialize(
|
||||
value,
|
||||
specifiedType: const FullType(int),
|
||||
)
|
||||
as int?;
|
||||
break;
|
||||
case 'links':
|
||||
@@ -324,7 +360,8 @@ class UserBuilder implements Builder<User, UserBuilder> {
|
||||
|
||||
String? _portfolioUrl;
|
||||
String? get portfolioUrl => _$this._portfolioUrl;
|
||||
set portfolioUrl(String? portfolioUrl) => _$this._portfolioUrl = portfolioUrl;
|
||||
set portfolioUrl(String? portfolioUrl) =>
|
||||
_$this._portfolioUrl = portfolioUrl;
|
||||
|
||||
String? _bio;
|
||||
String? get bio => _$this._bio;
|
||||
@@ -399,7 +436,11 @@ class UserBuilder implements Builder<User, UserBuilder> {
|
||||
r'User',
|
||||
'username',
|
||||
),
|
||||
name: BuiltValueNullFieldError.checkNotNull(name, r'User', 'name'),
|
||||
name: BuiltValueNullFieldError.checkNotNull(
|
||||
name,
|
||||
r'User',
|
||||
'name',
|
||||
),
|
||||
portfolioUrl: portfolioUrl,
|
||||
bio: bio,
|
||||
location: location,
|
||||
|
||||
@@ -37,20 +37,18 @@ class _PhotoDetailsState extends State<PhotoDetails> {
|
||||
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),
|
||||
),
|
||||
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'),
|
||||
),
|
||||
builder: (context, followLink) => TextButton(
|
||||
onPressed: followLink,
|
||||
child: const Text('Unsplash'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -55,13 +55,12 @@ class _PhotoSearchDialogState extends State<PhotoSearchDialog> {
|
||||
child: const Text('CANCEL'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed:
|
||||
_searchEnabled
|
||||
? () {
|
||||
widget.callback(_controller.text);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
: null,
|
||||
onPressed: _searchEnabled
|
||||
? () {
|
||||
widget.callback(_controller.text);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
: null,
|
||||
child: const Text('SEARCH'),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -29,16 +29,15 @@ class PolicyDialog extends StatelessWidget {
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.lightBlue,
|
||||
),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse(
|
||||
'https://policies.google.com/terms',
|
||||
);
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse(
|
||||
'https://policies.google.com/terms',
|
||||
);
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -55,14 +54,13 @@ class PolicyDialog extends StatelessWidget {
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.lightBlue,
|
||||
),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse('https://unsplash.com/terms');
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
final url = Uri.parse('https://unsplash.com/terms');
|
||||
if (await url_launcher.canLaunchUrl(url)) {
|
||||
await url_launcher.launchUrl(url);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -144,7 +144,9 @@ class _SplitState extends State<Split> {
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).dividerColor,
|
||||
borderRadius: BorderRadius.circular(Split.dividerMainAxisSize),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Split.dividerMainAxisSize,
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
height: isHorizontal ? 2.0 : Split.dividerMainAxisSize - 2.0,
|
||||
|
||||
@@ -69,13 +69,12 @@ class _UnsplashDialog extends StatelessWidget {
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Unsplash',
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashHomepage)) {
|
||||
throw 'Could not launch $_unsplashHomepage';
|
||||
}
|
||||
},
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashHomepage)) {
|
||||
throw 'Could not launch $_unsplashHomepage';
|
||||
}
|
||||
},
|
||||
style: const TextStyle(color: Colors.blue),
|
||||
),
|
||||
const TextSpan(
|
||||
@@ -88,16 +87,18 @@ class _UnsplashDialog extends StatelessWidget {
|
||||
),
|
||||
TextSpan(
|
||||
text: 'how Unsplash collects and uses data',
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashPrivacyPolicy)) {
|
||||
throw 'Could not launch $_unsplashPrivacyPolicy';
|
||||
}
|
||||
},
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
if (!await launchUrl(_unsplashPrivacyPolicy)) {
|
||||
throw 'Could not launch $_unsplashPrivacyPolicy';
|
||||
}
|
||||
},
|
||||
style: const TextStyle(color: Colors.blue),
|
||||
),
|
||||
const TextSpan(text: '.', style: TextStyle(color: Colors.grey)),
|
||||
const TextSpan(
|
||||
text: '.',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -46,34 +46,33 @@ class _UnsplashSearchContentState extends State<UnsplashSearchContent> {
|
||||
),
|
||||
),
|
||||
secondChild: Center(
|
||||
child:
|
||||
photoSearchModel.selectedPhoto != null
|
||||
? PhotoDetails(
|
||||
photo: photoSearchModel.selectedPhoto!,
|
||||
onPhotoSave: (photo) async {
|
||||
final saveLocation = await getSaveLocation(
|
||||
suggestedName: '${photo.id}.jpg',
|
||||
acceptedTypeGroups: [
|
||||
const XTypeGroup(
|
||||
label: 'JPG',
|
||||
extensions: ['jpg'],
|
||||
mimeTypes: ['image/jpeg'],
|
||||
),
|
||||
],
|
||||
child: photoSearchModel.selectedPhoto != null
|
||||
? PhotoDetails(
|
||||
photo: photoSearchModel.selectedPhoto!,
|
||||
onPhotoSave: (photo) async {
|
||||
final saveLocation = await getSaveLocation(
|
||||
suggestedName: '${photo.id}.jpg',
|
||||
acceptedTypeGroups: [
|
||||
const XTypeGroup(
|
||||
label: 'JPG',
|
||||
extensions: ['jpg'],
|
||||
mimeTypes: ['image/jpeg'],
|
||||
),
|
||||
],
|
||||
);
|
||||
if (saveLocation != null) {
|
||||
final fileData = await photoSearchModel.download(
|
||||
photo: photo,
|
||||
);
|
||||
if (saveLocation != null) {
|
||||
final fileData = await photoSearchModel.download(
|
||||
photo: photo,
|
||||
);
|
||||
final photoFile = XFile.fromData(
|
||||
fileData,
|
||||
mimeType: 'image/jpeg',
|
||||
);
|
||||
await photoFile.saveTo(saveLocation.path);
|
||||
}
|
||||
},
|
||||
)
|
||||
: Container(),
|
||||
final photoFile = XFile.fromData(
|
||||
fileData,
|
||||
mimeType: 'image/jpeg',
|
||||
);
|
||||
await photoFile.saveTo(saveLocation.path);
|
||||
}
|
||||
},
|
||||
)
|
||||
: Container(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -87,28 +86,27 @@ class _UnsplashSearchContentState extends State<UnsplashSearchContent> {
|
||||
|
||||
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)),
|
||||
),
|
||||
),
|
||||
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(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
name: desktop_photo_search
|
||||
name: desktop_photo_search_material
|
||||
description: Search for Photos, using the Unsplash API.
|
||||
publish_to: 'none'
|
||||
version: 1.0.0+1
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: ^3.7.0-0
|
||||
sdk: ^3.9.0-0
|
||||
|
||||
dependencies:
|
||||
built_collection: ^5.1.1
|
||||
@@ -20,7 +21,6 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/google/flutter-desktop-embedding.git
|
||||
path: plugins/menubar
|
||||
ref: 6c66ad23ee79749f30a8eece542cf54eaf157ed8
|
||||
provider: ^6.0.5
|
||||
transparent_image: ^2.0.1
|
||||
url_launcher: ^6.1.12
|
||||
@@ -29,7 +29,6 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/google/flutter-desktop-embedding.git
|
||||
path: plugins/window_size
|
||||
ref: 6c66ad23ee79749f30a8eece542cf54eaf157ed8
|
||||
|
||||
dev_dependencies:
|
||||
analysis_defaults:
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:desktop_photo_search/src/unsplash/photo.dart';
|
||||
import 'package:desktop_photo_search/src/unsplash/search_photos_response.dart';
|
||||
import 'package:desktop_photo_search/src/unsplash/unsplash.dart';
|
||||
import 'package:desktop_photo_search/src/unsplash/user.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/photo.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/search_photos_response.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/unsplash.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/user.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:http/testing.dart';
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:desktop_photo_search/src/model/photo_search_model.dart';
|
||||
import 'package:desktop_photo_search/src/unsplash/photo.dart';
|
||||
import 'package:desktop_photo_search/src/unsplash/search_photos_response.dart';
|
||||
import 'package:desktop_photo_search/src/unsplash/unsplash.dart';
|
||||
import 'package:desktop_photo_search_material/src/model/photo_search_model.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/photo.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/search_photos_response.dart';
|
||||
import 'package:desktop_photo_search_material/src/unsplash/unsplash.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
Reference in New Issue
Block a user