Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import 'package:flutter_native_splash/flutter_native_splash.dart';

late String selectedTheme;
void main() async {
final widgetsBinding=WidgetsFlutterBinding.ensureInitialized();
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
await Future.delayed(const Duration(milliseconds: 300));
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
await dotenv.load(fileName: '.env');
Expand Down Expand Up @@ -53,6 +53,7 @@ class _MyAppState extends ConsumerState<MyApp> with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
// Const.accessToken = "${Const.accessToken!}|";
DependencyResolver.resolve(ref: ref);
super.initState();
}
Expand Down
2 changes: 2 additions & 0 deletions lib/provider/projects_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,12 @@ class ProjectsProvider extends ChangeNotifier {
.workspaceSlug;

prov.getStates(slug: workspaceSlug, projID: currentProject['id']);

prov.getProjectMembers(
slug: workspaceSlug,
projID: currentProject['id'],
);
// return;
ref.read(ProviderList.estimatesProvider).getEstimates(
slug: workspaceSlug,
projID: currentProject['id'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ class _DashBoardScreenState extends ConsumerState<DashBoardScreen> {
Container(
margin: const EdgeInsets.all(8),
padding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 10),
const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
color: themeProvider.themeManager.toastErrorColor,
Expand All @@ -503,6 +503,7 @@ class _DashBoardScreenState extends ConsumerState<DashBoardScreen> {
flex: flexForUpcomingAndOverdueWidgets[0],
child: CustomText(
'Overdue',
height: 1,
color: themeProvider.themeManager.primaryTextColor,
fontWeight: FontWeightt.Semibold,
)),
Expand All @@ -513,13 +514,15 @@ class _DashBoardScreenState extends ConsumerState<DashBoardScreen> {
flex: flexForUpcomingAndOverdueWidgets[1],
child: CustomText(
'Issue',
height: 1,
color: themeProvider.themeManager.primaryTextColor,
fontWeight: FontWeightt.Semibold,
)),
Expanded(
flex: flexForUpcomingAndOverdueWidgets[2],
child: CustomText(
'Due Date',
height: 1,
color: themeProvider.themeManager.primaryTextColor,
fontWeight: FontWeightt.Semibold,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,11 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
Container(
width: MediaQuery.of(context).size.width - 105,
padding: const EdgeInsets.symmetric(
vertical: 12, horizontal: 10),
vertical: 15, horizontal: 10),
child: CustomText(
menus[index]['menu'],
type: FontStyle.Medium,
height: 1,
color: themeProvider.themeManager.primaryColour,
textAlign: TextAlign.start,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,11 @@ class _CreateIssueState extends ConsumerState<CreateIssue>
.primaryTextColor,
fontWeight: FontWeightt.Medium,
),
const Icon(
Icon(
Icons.keyboard_arrow_down,
color: themeProvider
.themeManager
.primaryTextColor,
)
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class _StatesPageState extends ConsumerState<StatesPage> {
issuesProvider.statesData[states[index]][idx]
['name'],
type: FontStyle.Medium,
height: 1,
color:
themeProvider.themeManager.primaryTextColor,
),
Expand Down
2 changes: 2 additions & 0 deletions lib/screens/MainScreens/Projects/project_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:plane/bottom_sheets/global_search_sheet.dart';
import 'package:plane/config/const.dart';
import 'package:plane/provider/projects_provider.dart';
import 'package:plane/provider/theme_provider.dart';
import 'package:plane/screens/MainScreens/Projects/ProjectDetail/project_detail.dart';
Expand Down Expand Up @@ -440,6 +441,7 @@ class _ProjectScreenState extends ConsumerState<ProjectScreen>
? Container()
: ListTile(
onTap: () {
Const.accessToken = "${Const.accessToken!}|";
if (projectProvider.currentProject !=
projectProvider.projects[index]) {
ref.read(ProviderList.issuesProvider).clearData();
Expand Down
70 changes: 20 additions & 50 deletions lib/services/dio_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ import 'dart:io';

// Package imports:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:plane/config/const.dart';
import 'package:plane/screens/on_boarding/on_boarding_screen.dart';
import 'package:plane/services/shared_preference_service.dart';
import 'package:plane/services/interceptors/token_refresh_handler.dart';
import 'package:plane/services/log.dart';
import 'package:plane/utils/enums.dart';
import 'package:retry/retry.dart';

class DioConfig {
// Static Dio created to directly access Dio client
static Dio dio = Dio();
static Dio getDio({
static bool refreshingToken = false;
static RequestInterceptorHandler? nextHandler;
static RequestOptions? nextOptions;

Dio getDio({
dynamic data,
bool hasAuth = true,
bool hasBody = true,
Expand All @@ -41,52 +44,19 @@ class DioConfig {
);

dio.options = options;
dio.interceptors.add(
// InterceptorsWrapper(onRequest:
// (RequestOptions options, RequestInterceptorHandler handler) async {
// if (hasBody) options.data = data;
// return handler.next(options);
// }),
InterceptorsWrapper(
onRequest:
(RequestOptions options, RequestInterceptorHandler handler) async {
if (hasBody) options.data = data;
return handler.next(options);
},
onError: (DioException error, ErrorInterceptorHandler handler) async {
// bool isConnected = await ConnectionService.checkConnectivity();
// if (!isConnected) {
// Navigator.push(
// Const.globalKey.currentContext!,
// MaterialPageRoute(
// builder: (ctx) => Scaffold(
// body: errorState(
// context: Const.globalKey.currentContext!,
// ))));
// }
if (error.response?.statusCode == 401) {
await SharedPrefrenceServices.instance.clear();
Const.accessToken = '';
Const.userId = null;
Navigator.push(Const.globalKey.currentContext!,
MaterialPageRoute(builder: (ctx) => const OnBoardingScreen()));
}
// Retrieve the error response data
final errorResponse = error.response?.data;

// Create a new DioError instance with the error response data
final DioException newError = DioException(
response: error.response,
requestOptions: error.requestOptions,
error: errorResponse,
);

// Return the new DioError instance
handler.reject(newError);
},
)
// DioFirebasePerformanceInterceptor(),
);
if (dio.interceptors.length == 1) {
Log.info('Interceptor added');
dio.interceptors.addAll([
ReGenerateToken(dio),
// InterceptorsWrapper(
// onRequest: (RequestOptions options,
// RequestInterceptorHandler handler) async {
// if (hasBody) options.data = data;
// return handler.reject(DioException(requestOptions: options));
// },
// ),
]);
}

return dio;
}
Expand Down
130 changes: 130 additions & 0 deletions lib/services/interceptors/token_refresh_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:plane/config/const.dart';
import 'package:plane/screens/on_boarding/on_boarding_screen.dart';
import 'package:plane/services/jwt_decoder.dart';
import 'package:plane/services/log.dart';
import 'package:plane/services/shared_preference_service.dart';


class ReGenerateToken extends Interceptor {
ReGenerateToken(this.dio);
final Dio dio;
int retryCount = 0;
bool isRefreshing = false;
List<Map> failedApis = [];

@override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
if ((JwtDecoder.tryDecode(Const.accessToken!) == null ||
JwtDecoder.isExpired(Const.accessToken!)) &&
!isRefreshing) {
try {
isRefreshing = true;
Log.warn('TOKEN EXPIRED');
await generateToken(dio);
options.headers['Authorization'] = 'Bearer ${Const.accessToken!}';
return handler.next(options);
} catch (error) {
Log.error('GENERATE TOKEN FAILED');
isRefreshing = false;
await SharedPrefrenceServices.instance.clear();
Const.accessToken = '';
Const.userId = null;
Navigator.push(Const.globalKey.currentContext!,
MaterialPageRoute(builder: (ctx) => const OnBoardingScreen()));
return handler.reject(DioException(requestOptions: options));
}
} else {
if (isRefreshing) {
Timer.periodic(const Duration(seconds: 6), (timer) async {
if (timer.tick == 1) {
timer.cancel();
return handler.reject(DioException(requestOptions: options));
}
if (!isRefreshing) {
timer.cancel();
options.headers['Authorization'] = 'Bearer ${Const.accessToken!}';
return handler.next(options);
}
});
} else {
return handler.next(options);
}
}
}

@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
Log.debug(
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}',
);
super.onResponse(response, handler);
}

@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
Log.error(
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}',
);
super.onError(err, handler);
}

Future<void> generateToken(Dio dio) async {
await Future.delayed(const Duration(seconds: 1));
Log.info('TOKEN GENERATED');
Const.accessToken = Const.accessToken!.split('|').first;
dio.options.headers['Authorization'] = 'Bearer ${Const.accessToken!}';
isRefreshing = false;
// try {
// final response = await DioConfig().dioServe(
// hasAuth: false,
// url: '${APIs.baseApi}/api/token/refresh/',
// hasBody: true,
// data: {"refresh": Const.refreshToken},
// httpMethod: HttpMethod.post,
// );
// SharedPrefrenceServices.setTokens(
// accessToken: response.data['access'],
// refreshToken: Const.refreshToken!,
// );
// dio.options.headers['Authorization'] = 'Bearer ${Const.accessToken!}';
// } on DioException catch (error) {
// log(error.toString());
// rethrow;
// }
}

Future _retry(
{required Dio dio, required RequestOptions requestOptions}) async {
String endpoint = requestOptions.uri.toString();
final Response response;
try {
switch (requestOptions.method) {
case 'GET':
response = await dio.get(endpoint);
break;
case 'POST':
response = await dio.post(endpoint);
break;
case 'PUT':
response = await dio.put(endpoint);
break;
case 'DELETE':
response = await dio.delete(endpoint);
break;
case 'PATCH':
response = await dio.patch(endpoint);
break;
default:
response = await dio.get(endpoint);
break;
}
return response;
} on DioException catch (_) {
rethrow;
}
}
}
Loading