-
Notifications
You must be signed in to change notification settings - Fork 382
ok_http
: Add BaseClient Implementation and make asynchronous requests.
#1215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
brianquinlan
merged 15 commits into
dart-lang:master
from
Anikate-De:ok_http_async_impl
May 31, 2024
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
1681e8b
add dependencies to pkgs/ok_http/pubspec.yaml
Anikate-De 546b1e1
ignore pkgs/ok_http/jar/
Anikate-De 4bd9c19
create jnigen config file (pkgs/ok_http/jnigen.yaml) and generate bin…
Anikate-De c07e573
add pkgs/ok_http/src/ok_http_client.dart and implement BaseClient's s…
Anikate-De 891db53
added usage docs and export in pkgs/ok_http/ok_http.dart
Anikate-De 8d005de
add http and testing deps to pkgs/ok_http/example/pubspec.yaml
Anikate-De 781ed6c
reuse the "books" example in pkgs/ok_http from pkgs/cronet_http
Anikate-De 6f7d32d
add okhttp dependency to pkgs/ok_http/android/build.gradle and bump u…
Anikate-De df99b97
add integration tests to pkgs/ok_http/example/
Anikate-De 81aba8a
add docs to pkgs/ok_http/ok_http_client.dart
Anikate-De 037a96c
update pkgs/ok_http/CHANGELOG.md
Anikate-De 8133bed
add test workflow to okhttp.yaml
Anikate-De bae6f5c
exclude jnigen files (pkgs/ok_http/lib/src/third_party) and sort pub …
Anikate-De d005a72
pkgs/ok_http: #1215 review fixes
Anikate-De f2eb9f3
[pkgs/ok_http]: Review fixes for #1215
Anikate-De File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
## 0.1.0-wip | ||
|
||
* Initial release. | ||
- Implementation of [`BaseClient`](https://pub.dev/documentation/http/latest/http/BaseClient-class.html) and `send()` method using [`enqueue()` API](https://square.github.io/okhttp/5.x/okhttp/okhttp3/-call/enqueue.html) | ||
- `ok_http` can now send asynchronous requests |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
include: ../../analysis_options.yaml | ||
|
||
analyzer: | ||
exclude: | ||
- lib/src/third_party/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. 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:http_client_conformance_tests/http_client_conformance_tests.dart'; | ||
import 'package:integration_test/integration_test.dart'; | ||
import 'package:ok_http/ok_http.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() async { | ||
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); | ||
|
||
await testConformance(); | ||
} | ||
|
||
Future<void> testConformance() async { | ||
group('ok_http client', () { | ||
testRequestBody(OkHttpClient()); | ||
testResponseBody(OkHttpClient(), canStreamResponseBody: false); | ||
testRequestHeaders(OkHttpClient()); | ||
testRequestMethods(OkHttpClient(), preservesMethodCase: true); | ||
testResponseStatusLine(OkHttpClient()); | ||
testCompressedResponseBody(OkHttpClient()); | ||
testIsolate(OkHttpClient.new); | ||
testResponseCookies(OkHttpClient(), canReceiveSetCookieHeaders: true); | ||
}); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
class Book { | ||
String title; | ||
String description; | ||
Uri imageUrl; | ||
|
||
Book(this.title, this.description, this.imageUrl); | ||
|
||
static List<Book> listFromJson(Map<dynamic, dynamic> json) { | ||
final books = <Book>[]; | ||
|
||
if (json['items'] case final List<dynamic> items) { | ||
for (final item in items) { | ||
if (item case {'volumeInfo': final Map<dynamic, dynamic> volumeInfo}) { | ||
if (volumeInfo | ||
case { | ||
'title': final String title, | ||
'description': final String description, | ||
'imageLinks': {'smallThumbnail': final String thumbnail} | ||
}) { | ||
books.add(Book(title, description, Uri.parse(thumbnail))); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return books; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,69 +1,149 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. 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:io'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'dart:async'; | ||
import 'package:http/http.dart'; | ||
import 'package:http/io_client.dart'; | ||
import 'package:http_image_provider/http_image_provider.dart'; | ||
import 'package:ok_http/ok_http.dart'; | ||
import 'package:provider/provider.dart'; | ||
|
||
import 'book.dart'; | ||
|
||
void main() { | ||
runApp(const MyApp()); | ||
final Client httpClient; | ||
if (Platform.isAndroid) { | ||
httpClient = OkHttpClient(); | ||
} else { | ||
httpClient = IOClient(HttpClient()..userAgent = 'Book Agent'); | ||
} | ||
|
||
runApp(Provider<Client>( | ||
create: (_) => httpClient, | ||
child: const BookSearchApp(), | ||
dispose: (_, client) => client.close())); | ||
} | ||
|
||
class MyApp extends StatefulWidget { | ||
const MyApp({super.key}); | ||
class BookSearchApp extends StatelessWidget { | ||
const BookSearchApp({super.key}); | ||
|
||
@override | ||
State<MyApp> createState() => _MyAppState(); | ||
Widget build(BuildContext context) => const MaterialApp( | ||
// Remove the debug banner. | ||
debugShowCheckedModeBanner: false, | ||
title: 'Book Search', | ||
home: HomePage(), | ||
); | ||
} | ||
|
||
class _MyAppState extends State<MyApp> { | ||
late int sumResult; | ||
late Future<int> sumAsyncResult; | ||
class HomePage extends StatefulWidget { | ||
const HomePage({super.key}); | ||
|
||
@override | ||
State<HomePage> createState() => _HomePageState(); | ||
} | ||
|
||
class _HomePageState extends State<HomePage> { | ||
List<Book>? _books; | ||
String? _lastQuery; | ||
late Client _client; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
_client = context.read<Client>(); | ||
} | ||
|
||
// Get the list of books matching `query`. | ||
// The `get` call will automatically use the `client` configured in `main`. | ||
Future<List<Book>> _findMatchingBooks(String query) async { | ||
final response = await _client.get( | ||
Uri.https( | ||
'www.googleapis.com', | ||
'/books/v1/volumes', | ||
{'q': query, 'maxResults': '20', 'printType': 'books'}, | ||
), | ||
); | ||
|
||
final json = jsonDecode(utf8.decode(response.bodyBytes)) as Map; | ||
return Book.listFromJson(json); | ||
} | ||
|
||
void _runSearch(String query) async { | ||
_lastQuery = query; | ||
if (query.isEmpty) { | ||
setState(() { | ||
_books = null; | ||
}); | ||
return; | ||
} | ||
|
||
final books = await _findMatchingBooks(query); | ||
// Avoid the situation where a slow-running query finishes late and | ||
// replaces newer search results. | ||
if (query != _lastQuery) return; | ||
setState(() { | ||
_books = books; | ||
}); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
const textStyle = TextStyle(fontSize: 25); | ||
const spacerSmall = SizedBox(height: 10); | ||
return MaterialApp( | ||
home: Scaffold( | ||
appBar: AppBar( | ||
title: const Text('Native Packages'), | ||
), | ||
body: SingleChildScrollView( | ||
child: Container( | ||
padding: const EdgeInsets.all(10), | ||
child: Column( | ||
children: [ | ||
const Text( | ||
'', | ||
style: textStyle, | ||
textAlign: TextAlign.center, | ||
), | ||
spacerSmall, | ||
Text( | ||
'sum(1, 2) = $sumResult', | ||
style: textStyle, | ||
textAlign: TextAlign.center, | ||
), | ||
spacerSmall, | ||
FutureBuilder<int>( | ||
future: sumAsyncResult, | ||
builder: (BuildContext context, AsyncSnapshot<int> value) { | ||
final displayValue = | ||
(value.hasData) ? value.data : 'loading'; | ||
return Text( | ||
'await sumAsync(3, 4) = $displayValue', | ||
style: textStyle, | ||
textAlign: TextAlign.center, | ||
); | ||
}, | ||
), | ||
], | ||
final searchResult = _books == null | ||
? const Text('Please enter a query', style: TextStyle(fontSize: 24)) | ||
: _books!.isNotEmpty | ||
? BookList(_books!) | ||
: const Text('No results found', style: TextStyle(fontSize: 24)); | ||
|
||
return Scaffold( | ||
appBar: AppBar(title: const Text('Book Search')), | ||
body: Padding( | ||
padding: const EdgeInsets.all(10), | ||
child: Column( | ||
children: [ | ||
const SizedBox(height: 20), | ||
TextField( | ||
onChanged: _runSearch, | ||
decoration: const InputDecoration( | ||
labelText: 'Search', | ||
suffixIcon: Icon(Icons.search), | ||
), | ||
), | ||
), | ||
const SizedBox(height: 20), | ||
Expanded(child: searchResult), | ||
], | ||
), | ||
), | ||
); | ||
} | ||
} | ||
|
||
class BookList extends StatefulWidget { | ||
final List<Book> books; | ||
const BookList(this.books, {super.key}); | ||
|
||
@override | ||
State<BookList> createState() => _BookListState(); | ||
} | ||
|
||
class _BookListState extends State<BookList> { | ||
@override | ||
Widget build(BuildContext context) => ListView.builder( | ||
itemCount: widget.books.length, | ||
itemBuilder: (context, index) => Card( | ||
key: ValueKey(widget.books[index].title), | ||
child: ListTile( | ||
leading: Image( | ||
image: HttpImage( | ||
widget.books[index].imageUrl.replace(scheme: 'https'), | ||
client: context.read<Client>())), | ||
title: Text(widget.books[index].title), | ||
subtitle: Text(widget.books[index].description), | ||
), | ||
), | ||
); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.