-
Notifications
You must be signed in to change notification settings - Fork 7.7k
/
Copy pathunsplash.dart
121 lines (102 loc) · 3.36 KB
/
unsplash.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart: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(json.encode(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}');
unawaited(
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';
}
}