Skip to content

Commit ed87dc7

Browse files
Merge pull request #25 from viraj-webelight/v0.0.16_release
Jwt Hero Implementation
2 parents 6aa20a6 + 70dd4db commit ed87dc7

23 files changed

+490
-177
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
#
2+
3+
## 0.0.15
4+
5+
* Removed Image Cropper
6+
* Added JWT Refresh Token Interceptor
7+
18
## 0.0.14
29

310
* Replaced discontinued Flutter root detection package.

example/lib/views/example_view.dart

Lines changed: 14 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ class ExampleView extends StatelessWidget {
3636
AppTextField(
3737
focusNode: focusNode,
3838
label: "TextField to View Done Keyboard",
39-
showDoneKeyboard:
40-
true, // by default done view is false
39+
showDoneKeyboard: true, // by default done view is false
4140
showExtraHeight: isFocusNode,
4241
),
4342
ElevatedButton(
@@ -77,108 +76,57 @@ class ExampleView extends StatelessWidget {
7776
),
7877
ElevatedButton(
7978
onPressed: () async {
80-
await DialogHelper.showActionSheet<
81-
PickerActionType>(
79+
await DialogHelper.showActionSheet<PickerActionType>(
8280
actions: const [
83-
SheetAction(
84-
key: PickerActionType.camera,
85-
label: "Camera"),
86-
SheetAction(
87-
key: PickerActionType.gallery,
88-
label: "Galley"),
81+
SheetAction(key: PickerActionType.camera, label: "Camera"),
82+
SheetAction(key: PickerActionType.gallery, label: "Galley"),
8983
],
9084
);
9185
},
9286
child: const Text("Show Action Bottom Sheet"),
9387
),
9488
Padding(
95-
padding: const EdgeInsets.symmetric(
96-
horizontal: 40.0, vertical: 30.0),
89+
padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 30.0),
9790
child: AppNetworkImage(
9891
url:
9992
"https://images.unsplash.com/photo-1500622944204-b135684e99fd?q=80&w=2061&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
100-
errorWidget: (p0, p1, p2) =>
101-
const Icon(Icons.error),
93+
errorWidget: (p0, p1, p2) => const Icon(Icons.error),
10294
),
10395
),
10496
ElevatedButton(
10597
onPressed: () {
106-
PreferenceHelper.setStringPrefValue(
107-
key: "setString", value: "showData");
98+
PreferenceHelper.setStringPrefValue(key: "setString", value: "showData");
10899
},
109100
child: const Text("Set Value in Shared Preference"),
110101
),
111102
ElevatedButton(
112103
onPressed: () async {
113-
String getValue =
114-
PreferenceHelper.getStringPrefValue(
115-
key: "setString");
104+
String getValue = PreferenceHelper.getStringPrefValue(key: "setString");
116105
LogHelper.logInfo("getValue $getValue");
117106
},
118107
child: const Text("Get Value in Shared Preference"),
119108
),
120109
ElevatedButton(
121110
onPressed: () async {
122-
bool isRemoved =
123-
await PreferenceHelper.removePrefValue(
124-
key: "setString");
111+
bool isRemoved = await PreferenceHelper.removePrefValue(key: "setString");
125112
LogHelper.logInfo("isRemoved $isRemoved");
126113
},
127-
child:
128-
const Text("remove Value in Shared Preference"),
114+
child: const Text("remove Value in Shared Preference"),
129115
),
130116
ElevatedButton(
131117
onPressed: () async {
132-
final fileResult =
133-
await ImagePickerHelper.multiMediaPicker();
118+
final fileResult = await ImagePickerHelper.multiMediaPicker();
134119
LogHelper.logInfo("result $fileResult");
135120
},
136121
child: const Text("Multimedia Picker"),
137122
),
138123
ElevatedButton(
139124
onPressed: () {
140-
final time = DateTime.now().toCustomFormatter(
141-
formatter: DateTimeFormatter.HOUR_MINUTE);
125+
final time = DateTime.now().toCustomFormatter(formatter: DateTimeFormatter.HOUR_MINUTE);
142126
LogHelper.logInfo("DateTime $time");
143127
},
144128
child: const Text("DateTime Extesion"),
145129
),
146-
ElevatedButton(
147-
onPressed: () async {
148-
PermissionHandlerService.handlePermissions(
149-
type: PermissionType.PHOTO,
150-
151-
/// You can pass custom Dialog
152-
permissionDeniedDialog: () {
153-
return showDialog(
154-
context: context,
155-
builder: (context) {
156-
return const AlertDialog(
157-
title: Text("Custom Dialog"),
158-
);
159-
},
160-
);
161-
},
162-
callBack: () async {
163-
final fileResult =
164-
await ImagePickerHelper.customMediaPicker(
165-
pickerActionType: PickerActionType.gallery,
166-
);
167-
LogHelper.logInfo("result $fileResult");
168-
if (fileResult != null) {
169-
croppedImage.value =
170-
await ImageCropperHelper.cropImage(
171-
imagePath: fileResult.path,
172-
);
173-
174-
LogHelper.logInfo(
175-
"croppedImage result $croppedImage");
176-
}
177-
},
178-
);
179-
},
180-
child: const Text("Image Cropper"),
181-
),
182130
const SizedBox(height: 20.0),
183131
const Padding(
184132
padding: EdgeInsets.all(20.0),
@@ -189,15 +137,13 @@ class ExampleView extends StatelessWidget {
189137
trimMode: TrimMode.Line,
190138
trimCollapsedText: 'Show more',
191139
trimExpandedText: 'Show less',
192-
moreStyle: TextStyle(
193-
fontSize: 14, fontWeight: FontWeight.bold),
140+
moreStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
194141
),
195142
),
196143
const SizedBox(height: 20.0),
197144
if (croppedImage.value?.path.isNotEmpty ?? false)
198145
Padding(
199-
padding: const EdgeInsets.symmetric(
200-
horizontal: 40.0, vertical: 30.0),
146+
padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 30.0),
201147
child: Image.file(croppedImage.value ?? File('')),
202148
),
203149
if (isFocusNode.value) const SizedBox(height: 60),

example/linux/flutter/generated_plugins.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
list(APPEND FLUTTER_PLUGIN_LIST
66
dynamic_color
77
file_selector_linux
8+
flutter_secure_storage_linux
89
)
910

1011
list(APPEND FLUTTER_FFI_PLUGIN_LIST

lib/master_utility.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export 'package:fluttertoast/fluttertoast.dart';
99
export 'package:image_picker_platform_interface/src/types/camera_device.dart';
1010
export 'package:master_utility/src/api_helper/api_service.dart';
1111
export 'package:master_utility/src/api_helper/dio_client.dart';
12+
export 'package:master_utility/src/api_helper/interceptor/jwt/jwt_hero.dart';
13+
export 'package:master_utility/src/api_helper/interceptor/jwt/refresh_token_configuration_mode_class.dart';
1214
export 'package:master_utility/src/api_helper/mix_panel_event_model.dart';
1315
export 'package:master_utility/src/api_status_code_enum.dart';
1416
export 'package:master_utility/src/auto_size_text_helper.dart';
@@ -20,7 +22,6 @@ export 'package:master_utility/src/double_click_redunt_helper.dart';
2022
export 'package:master_utility/src/email_dispose_helper.dart';
2123
export 'package:master_utility/src/encryption.dart';
2224
export 'package:master_utility/src/encryption_service.dart';
23-
export 'package:master_utility/src/image_cropper_helper.dart';
2425
export 'package:master_utility/src/image_picker_helper.dart';
2526
export 'package:master_utility/src/intl_mobile/intl_phone_field.dart';
2627
export 'package:master_utility/src/jwt_helper.dart';

lib/src/api_helper/dio_client.dart

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
// Dart imports:
22
import 'dart:io';
33

4-
// Package imports:
5-
import 'package:dio/dio.dart';
64
import 'package:dio_http_formatter/dio_http_formatter.dart';
75
// Flutter imports:
86
import 'package:flutter/foundation.dart';
7+
import 'package:master_utility/master_utility.dart';
98
// Project imports:
109
import 'package:master_utility/src/api_helper/interceptor/authorization.dart';
1110
import 'package:master_utility/src/api_helper/interceptor/curl_logger.dart';
@@ -14,8 +13,8 @@ DioClient dioClient = DioClient();
1413

1514
class DioClient {
1615
Dio? _dio;
16+
RefreshTokenConfiguration? _refreshTokenConfiguration;
1717

18-
void Function(DioException, ErrorInterceptorHandler)? globalOnErrorHandler;
1918
Dio getDioClient({
2019
bool isAuth = true,
2120
void Function(
@@ -27,7 +26,8 @@ class DioClient {
2726

2827
final interceptors = <Interceptor>[];
2928

30-
if (isAuth) {
29+
/// This will load access token from [PreferenceHelper]
30+
if (_refreshTokenConfiguration == null && isAuth) {
3131
interceptors.add(AuthTokenInterceptor());
3232
}
3333

@@ -36,21 +36,47 @@ class DioClient {
3636
interceptors.add(CurlLoggerDioInterceptor(printOnSuccess: true));
3737
}
3838

39-
interceptors.addAll([
39+
interceptors.add(
4040
InterceptorsWrapper(onError: callback),
41-
if (globalOnErrorHandler != null) ...[InterceptorsWrapper(onError: globalOnErrorHandler)],
42-
]);
41+
);
42+
43+
if (_refreshTokenConfiguration != null) {
44+
_addJWTInterceptor(_refreshTokenConfiguration!);
45+
}
4346

4447
_dio?.interceptors.addAll(interceptors);
4548

4649
return _dio!;
4750
}
4851

49-
DioClient setConfiguration(String baseUrl,
50-
{Map<String, dynamic>? headers, void Function(DioException, ErrorInterceptorHandler)? globalOnErrorHandler}) {
51-
if (globalOnErrorHandler != null) {
52-
this.globalOnErrorHandler = globalOnErrorHandler;
53-
}
52+
DioClient setRefreshTokenConfiguration({
53+
required RefreshTokenConfiguration refreshTokenConfiguration,
54+
}) {
55+
_refreshTokenConfiguration = refreshTokenConfiguration;
56+
_addJWTInterceptor(refreshTokenConfiguration);
57+
return this;
58+
}
59+
60+
void _addJWTInterceptor(RefreshTokenConfiguration config) {
61+
_dio?.interceptors.add(
62+
JwtHeroInterceptor(
63+
tokenStorage: config.tokenStorage,
64+
baseClient: _dio ?? Dio(),
65+
onRefresh: (refreshClient, refreshToken) async {
66+
refreshClient.options = refreshClient.options.copyWith(headers: {config.refreshTokenHeaderKey: refreshToken});
67+
final response = await refreshClient.post(config.refreshTokenEndPoint);
68+
final token = config.responseMapper(response.data);
69+
return token;
70+
},
71+
sessionManager: config.sessionManager,
72+
),
73+
);
74+
}
75+
76+
DioClient setConfiguration(
77+
String baseUrl, {
78+
Map<String, dynamic>? headers,
79+
}) {
5480
BaseOptions options = BaseOptions(
5581
connectTimeout: const Duration(
5682
milliseconds: 30000,

lib/src/api_helper/interceptor/authorization.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ import 'package:master_utility/master_utility.dart';
88

99
class AuthTokenInterceptor extends Interceptor {
1010
@override
11-
void onRequest(
12-
RequestOptions options, RequestInterceptorHandler handler) async {
13-
final String accessToken = PreferenceHelper.getStringPrefValue(
14-
key: HttpHeaders.authorizationHeader);
11+
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
12+
final String accessToken = PreferenceHelper.getStringPrefValue(key: HttpHeaders.authorizationHeader);
1513

1614
options.headers[HttpHeaders.authorizationHeader] = "Bearer $accessToken";
1715

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export 'package:master_utility/src/api_helper/interceptor/jwt/jwt_hero_interceptor.dart';
2+
export 'package:master_utility/src/api_helper/interceptor/jwt/jwt_token.dart';
3+
export 'package:master_utility/src/api_helper/interceptor/jwt/session_manager.dart';
4+
export 'package:master_utility/src/api_helper/interceptor/jwt/token_storage.dart';

0 commit comments

Comments
 (0)