Skip to content

Commit cce341f

Browse files
committed
fixes
1 parent 284b4fa commit cce341f

File tree

11 files changed

+324
-204
lines changed

11 files changed

+324
-204
lines changed

lib/data/remote/api_service.dart

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@ import 'dart:async';
22
import 'dart:convert';
33
import 'dart:io';
44

5-
import 'package:flutter/foundation.dart' show debugPrint;
6-
import 'package:http/http.dart' as http;
7-
import 'package:path/path.dart' as path;
85
import 'package:node_auth/data/constants.dart';
9-
import 'package:node_auth/data/exception/remote_data_source_exception.dart';
106
import 'package:node_auth/data/remote/network_utils.dart';
117
import 'package:node_auth/data/remote/remote_data_source.dart';
128
import 'package:node_auth/data/remote/response/token_response.dart';
@@ -121,30 +117,16 @@ class ApiService implements RemoteDataSource {
121117
Future<UserResponse> uploadImage(
122118
File file,
123119
String email,
120+
String token,
124121
) async {
125122
final url = Uri.https(baseUrl, '/users/upload');
126-
final stream = http.ByteStream(file.openRead());
127-
final length = await file.length();
128-
final request = http.MultipartRequest('POST', url)
129-
..fields['user'] = email
130-
..files.add(
131-
http.MultipartFile(
132-
'my_image',
133-
stream,
134-
length,
135-
filename: path.basename(file.path),
136-
),
137-
);
138-
final streamedResponse = await request.send();
139-
final statusCode = streamedResponse.statusCode;
140-
final decoded = json.decode(await streamedResponse.stream.bytesToString());
141-
142-
debugPrint('decoded: $decoded');
143-
144-
if (statusCode < 200 || statusCode >= 300) {
145-
throw RemoteDataSourceException(statusCode, decoded['message']);
146-
}
147-
123+
final decoded = await NetworkUtils.multipartPost(
124+
url,
125+
file,
126+
'my_image',
127+
fields: {'user': email},
128+
headers: {xAccessToken: token},
129+
);
148130
return UserResponse.fromJson(decoded);
149131
}
150132
}

lib/data/remote/network_utils.dart

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,66 @@
11
import 'dart:convert';
2+
import 'dart:io';
23

4+
import 'package:flutter/foundation.dart';
35
import 'package:http/http.dart' as http;
46
import 'package:node_auth/data/exception/remote_data_source_exception.dart';
7+
import 'package:path/path.dart' as path;
8+
9+
final _indent = ' ' * 11;
10+
11+
void _logRequest(
12+
Uri url,
13+
String method, {
14+
Map<String, String> headers,
15+
Map<String, String> body,
16+
Map<String, String> multipartFields,
17+
List<http.MultipartFile> multipartFiles,
18+
}) {
19+
debugPrint('[http] --> ${method} ${url}');
20+
debugPrint('${_indent}headers: $headers');
21+
22+
if (method == 'POST' || method == 'PUT') {
23+
debugPrint('${_indent}body: $body');
24+
25+
if (method == 'POST') {
26+
if (multipartFields != null) {
27+
debugPrint('${_indent}multipartFields: ${multipartFields}');
28+
}
29+
if (multipartFields != null) {
30+
debugPrint('${_indent}multipartFiles: ${multipartFiles}');
31+
}
32+
}
33+
}
34+
}
35+
36+
void _logResponse(http.Response response) {
37+
debugPrint('[http] <-- ${response.statusCode} ${response.request}');
38+
debugPrint('${_indent}bodyBytes: ${response.bodyBytes?.length}');
39+
try {
40+
debugPrint('${_indent}body: ' + response.body);
41+
} catch (_) {}
42+
}
543

644
class NetworkUtils {
745
static Future get(
846
Uri url, {
947
Map<String, String> headers,
1048
}) async {
49+
_logRequest(url, 'GET', headers: headers);
50+
1151
final response = await http.get(url, headers: headers);
52+
_logResponse(response);
53+
return _parse(response);
54+
}
55+
56+
static dynamic _parse(http.Response response) {
1257
final body = response.body;
1358
final statusCode = response.statusCode;
59+
1460
if (body == null) {
1561
throw RemoteDataSourceException(statusCode, 'Response body is null');
1662
}
63+
1764
final decoded = json.decode(body);
1865
if (statusCode < 200 || statusCode >= 300) {
1966
throw RemoteDataSourceException(statusCode, decoded['message']);
@@ -39,6 +86,8 @@ class NetworkUtils {
3986
Map<String, String> headers,
4087
Map<String, String> body,
4188
}) async {
89+
_logRequest(url, method, headers: headers, body: body);
90+
4291
final request = http.Request(method, url);
4392
if (body != null) {
4493
request.bodyFields = body;
@@ -48,25 +97,55 @@ class NetworkUtils {
4897
}
4998
final streamedResponse = await request.send();
5099

51-
final statusCode = streamedResponse.statusCode;
52-
final decoded = json.decode(await streamedResponse.stream.bytesToString());
53-
54-
if (statusCode < 200 || statusCode >= 300) {
55-
throw RemoteDataSourceException(statusCode, decoded['message']);
56-
}
57-
58-
return decoded;
100+
final response = await http.Response.fromStream(streamedResponse);
101+
_logResponse(response);
102+
return _parse(response);
59103
}
60104

61105
static Future put(
62106
Uri url, {
63107
Map<String, String> headers,
64-
body,
108+
Map<String, String> body,
65109
}) =>
66110
_helper(
67111
'PUT',
68112
url,
69113
headers: headers,
70114
body: body,
71115
);
116+
117+
static Future multipartPost(
118+
Uri url,
119+
File file,
120+
String field, {
121+
Map<String, String> headers,
122+
Map<String, String> fields,
123+
}) async {
124+
final stream = http.ByteStream(file.openRead());
125+
final length = await file.length();
126+
127+
final request = http.MultipartRequest('POST', url)
128+
..fields.addAll(fields ?? {})
129+
..files.add(
130+
http.MultipartFile(
131+
field,
132+
stream,
133+
length,
134+
filename: path.basename(file.path),
135+
),
136+
)
137+
..headers.addAll(headers ?? {});
138+
_logRequest(
139+
url,
140+
'POST',
141+
headers: headers,
142+
multipartFields: request.fields,
143+
multipartFiles: request.files,
144+
);
145+
final streamedResponse = await request.send();
146+
147+
final response = await http.Response.fromStream(streamedResponse);
148+
_logResponse(response);
149+
return _parse(response);
150+
}
72151
}

lib/data/remote/remote_data_source.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,9 @@ abstract class RemoteDataSource {
2727

2828
Future<UserResponse> getUserProfile(String email, String token);
2929

30-
Future<UserResponse> uploadImage(File file, String email);
30+
Future<UserResponse> uploadImage(
31+
File file,
32+
String email,
33+
String token,
34+
);
3135
}

lib/data/user_repository_imp.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class UserRepositoryImpl implements UserRepository {
103103
() => _remoteDataSource.uploadImage(
104104
image,
105105
userAndToken.user.email,
106+
userAndToken.token,
106107
),
107108
).flatMapResult(
108109
(user) => _execute(

lib/main.dart

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import 'package:disposebag/disposebag.dart';
1+
import 'package:disposebag/disposebag.dart' show DisposeBag, defaultLogger;
2+
import 'package:flutter/foundation.dart'
3+
show debugPrint, debugPrintSynchronously, kReleaseMode;
24
import 'package:flutter/material.dart';
35
import 'package:flutter/services.dart';
46
import 'package:flutter_provider/flutter_provider.dart';
@@ -9,19 +11,18 @@ import 'package:node_auth/data/remote/api_service.dart';
911
import 'package:node_auth/data/remote/remote_data_source.dart';
1012
import 'package:node_auth/data/user_repository_imp.dart';
1113
import 'package:node_auth/domain/repositories/user_repository.dart';
12-
import 'package:rx_shared_preferences/rx_shared_preferences.dart';
14+
import 'package:rx_shared_preferences/rx_shared_preferences.dart'
15+
show DefaultLogger, RxSharedPreferences, RxSharedPreferencesConfigs;
1316

1417
void main() async {
1518
WidgetsFlutterBinding.ensureInitialized();
16-
// DisposeBag.logger = null;
17-
19+
_setupLoggers();
1820
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
1921

2022
// construct RemoteDataSource
2123
const RemoteDataSource remoteDataSource = ApiService();
2224

2325
// construct LocalDataSource
24-
// RxSharedPreferencesConfigs.logger = null;
2526
final rxPrefs = RxSharedPreferences.getInstance();
2627
final LocalDataSource localDataSource = SharedPrefUtil(rxPrefs);
2728

@@ -38,3 +39,11 @@ void main() async {
3839
),
3940
);
4041
}
42+
43+
void _setupLoggers() {
44+
// set loggers to `null` to disable logging.
45+
DisposeBag.logger = kReleaseMode ? null : defaultLogger;
46+
RxSharedPreferencesConfigs.logger =
47+
kReleaseMode ? null : const DefaultLogger();
48+
debugPrint = kReleaseMode ? null : debugPrintSynchronously;
49+
}

lib/pages/home/home_profile_widget.dart

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:node_auth/data/constants.dart';
77
import 'package:node_auth/domain/models/auth_state.dart';
88
import 'package:node_auth/domain/models/user.dart';
99
import 'package:node_auth/pages/home/home_bloc.dart';
10+
import 'package:octo_image/octo_image.dart';
1011

1112
class HomeUserProfile extends StatelessWidget {
1213
const HomeUserProfile({Key key}) : super(key: key);
@@ -30,34 +31,59 @@ class HomeUserProfile extends StatelessWidget {
3031
final user = data.userAndToken?.user;
3132
return user == null
3233
? _buildUnauthenticated(context)
33-
: _buildProfile(user, homeBloc);
34+
: _buildProfile(user, homeBloc, context);
3435
},
3536
),
3637
),
3738
);
3839
}
3940

40-
Widget _buildProfile(User user, HomeBloc homeBloc) {
41+
Widget _buildProfile(User user, HomeBloc homeBloc, BuildContext context) {
42+
final image = OctoImage(
43+
image: user.imageUrl != null
44+
? NetworkImage(
45+
Uri.https(
46+
baseUrl,
47+
user.imageUrl,
48+
).toString(),
49+
)
50+
: AssetImage('assets/user.png'),
51+
fit: BoxFit.cover,
52+
width: 90.0,
53+
height: 90.0,
54+
progressIndicatorBuilder: (_, __) => Center(
55+
child: CircularProgressIndicator(
56+
strokeWidth: 2,
57+
),
58+
),
59+
errorBuilder: (_, __, ___) {
60+
final themeData = Theme.of(context);
61+
62+
return Center(
63+
child: Column(
64+
mainAxisAlignment: MainAxisAlignment.center,
65+
children: <Widget>[
66+
Icon(
67+
Icons.error,
68+
color: themeData.accentColor,
69+
),
70+
SizedBox(height: 4),
71+
Text(
72+
'Error',
73+
style: themeData.textTheme.subtitle2.copyWith(fontSize: 12),
74+
),
75+
],
76+
),
77+
);
78+
},
79+
);
80+
4181
return Row(
4282
crossAxisAlignment: CrossAxisAlignment.center,
4383
children: <Widget>[
4484
ClipOval(
4585
child: GestureDetector(
46-
child: user.imageUrl != null
47-
? Image.network(
48-
Uri.https(
49-
baseUrl,
50-
user.imageUrl,
51-
).toString(),
52-
fit: BoxFit.cover,
53-
width: 90.0,
54-
height: 90.0,
55-
)
56-
: Image.asset(
57-
'assets/user.png',
58-
width: 90.0,
59-
height: 90.0,
60-
),
86+
child: image,
6187
onTap: () => _pickAndUploadImage(homeBloc),
6288
),
6389
),

0 commit comments

Comments
 (0)