Skip to content

Commit

Permalink
Merge pull request #6 from Dat-TG/milestone-3
Browse files Browse the repository at this point in the history
Milestone 3
  • Loading branch information
Dat-TG authored Dec 30, 2023
2 parents 4c7167f + ad9bf83 commit 0b8d307
Show file tree
Hide file tree
Showing 178 changed files with 3,165 additions and 1,414 deletions.
3 changes: 1 addition & 2 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ linter:
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
6 changes: 6 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
android:label="LetTutor"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id"/>
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token"/>
<activity
android:name=".MainActivity"
android:exported="true"
Expand Down
5 changes: 5 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="facebook_app_id">868392621641182</string>
<string name="facebook_client_token">dd6fd3999d5fe99d773f8a8e9e877f7a</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"installed":{"client_id":"157247432892-sqk0gq6q94c2be14uq0v23qfmol34pno.apps.googleusercontent.com","project_id":"lettutor-407509","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"}}
17 changes: 17 additions & 0 deletions lib/core/dio/dio.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:dio/dio.dart';
import 'package:let_tutor/core/interceptors/auth_interceptor.dart';
import 'package:let_tutor/core/utils/constants.dart';

class DioClient {
static Dio getInstance() {
final Dio dio = Dio(BaseOptions(
baseUrl: AppConstants.baseUrl,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
));

dio.interceptors.add(AuthInterceptor(dio));

return dio;
}
}
87 changes: 87 additions & 0 deletions lib/core/interceptors/auth_interceptor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:dio/dio.dart';
import 'package:let_tutor/injection_container.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AuthInterceptor extends Interceptor {
final Dio dio;

AuthInterceptor(this.dio);

@override
Future<void> onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
// Retrieve token from wherever it's stored (e.g., SharedPreferences)
final String? token = sl<SharedPreferences>()
.getString('access-token'); // Implement this function to get the token

if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}

print(
'Request: ${options.method} ${options.headers} ${options.path} ${options.queryParameters}');

return handler.next(options);
}

@override
Future<void> onResponse(
Response response, ResponseInterceptorHandler handler) async {
print(
'Response: ${response.statusCode} ${response.headers} ${response.data}');
return handler.next(response);
}

@override
Future<void> onError(
DioException err, ErrorInterceptorHandler handler) async {
print('Error: ${err.response?.statusCode} ${err.response!.headers}');
if (err.response?.statusCode == 401) {
// Refresh token
final String? refreshToken = sl<SharedPreferences>().getString(
'refresh-token'); // Implement this function to get the token

if (refreshToken != null) {
final response = await dio.post(
'/auth/refresh-token',
data: {
'refreshToken': refreshToken,
'timezone': DateTime.now().timeZoneOffset.inHours,
},
);
if (response.statusCode == 200) {
// Save new tokens
final data = response.data;
sl<SharedPreferences>().setString(
'access-token', response.data['tokens']['access']['token']);
sl<SharedPreferences>()
.setString('refresh-token', data['tokens']['refresh']['token']);

// Retry
RequestOptions options = err.requestOptions;
final retryResponse = await dio.request(err.requestOptions.path,
options: Options(
method: options.method,
headers: options.headers,
extra: options.extra,
contentType: options.contentType,
responseType: options.responseType,
validateStatus: options.validateStatus,
receiveTimeout: options.receiveTimeout,
sendTimeout: options.sendTimeout,
followRedirects: options.followRedirects,
maxRedirects: options.maxRedirects,
requestEncoder: options.requestEncoder,
responseDecoder: options.responseDecoder,
listFormat: options.listFormat,
));
return handler.resolve(retryResponse);
}
}
}

return handler.next(err);
}
}
6 changes: 3 additions & 3 deletions lib/core/routers/my_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:let_tutor/core/common/appbar_normal.dart';
import 'package:let_tutor/core/common/bottom_bar.dart';
import 'package:let_tutor/domain/entities/course_details/course_details_entity.dart';
import 'package:let_tutor/domain/entities/message/message_entity.dart';
import 'package:let_tutor/domain/entities/wallet/transaction_entity.dart';
import 'package:let_tutor/presentation/become-tutor/become_tutor_screen.dart';
import 'package:let_tutor/presentation/booking/book_lesson_screen.dart';
import 'package:let_tutor/presentation/conversation/conversation_screen.dart';
Expand Down Expand Up @@ -285,7 +286,8 @@ class MyRouter {
return Helpers.buildPageWithDefaultTransition<void>(
context: context,
state: state,
child: const TransactionsScreen(),
child: TransactionsScreen(
transactions: state.extra as List<TransactionEntity>),
);
}),
GoRoute(
Expand All @@ -299,7 +301,5 @@ class MyRouter {
);
}),
],
// TODO: Add Error Handler
// TODO Add Redirect
);
}
2 changes: 2 additions & 0 deletions lib/core/utils/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class AppConstants {
};

static const Map<int, String> courseLevels = {
0: 'Any Level',
1: 'Beginner',
2: 'Upper-Beginner',
3: 'Pre-Intermediate',
Expand Down Expand Up @@ -72,4 +73,5 @@ class AppConstants {
];

static const baseUrl = 'https://sandbox.api.lettutor.com';
static const meetingServerUrl = "https://meet.lettutor.com";
}
9 changes: 7 additions & 2 deletions lib/core/utils/jitsi_meet_methods.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ class JitsiMeetMethods {
DateTime? nextLessonTime}) async {
// Define meetings options here
featureFlags ??= {};
serverUrl ??= 'https://meet.lettutor.com';
featureFlags['WATERMARK_ENABLED'] = true;
var options = JitsiMeetingOptions(
roomNameOrUrl: roomNameOrUrl,
serverUrl: serverUrl,
serverUrl: serverUrl ?? 'https://meet.lettutor.com',
subject: subject,
token: token,
isAudioMuted: isAudioMuted,
Expand Down Expand Up @@ -57,6 +57,7 @@ class JitsiMeetMethods {
},
onConferenceJoined: (url) {
debugPrint("onConferenceJoined: url: $url");

timer = Timer.periodic(const Duration(seconds: 1), (timer) {
String strTimeUntil = Helpers.getUntilLessonTime(
nextLessonTime ?? DateTime.now(), context);
Expand All @@ -65,6 +66,8 @@ class JitsiMeetMethods {
DateTime.now().millisecondsSinceEpoch) {
timer.cancel();
} else {
print('show toast $strTimeUntil');

Fluttertoast.showToast(
msg:
"$strTimeUntil ${AppLocalizations.of(context)!.untilLessonStart}\n(${DateFormat("EEEE, d MMMM y hh:mm", locale).format(nextLessonTime)})",
Expand All @@ -81,6 +84,7 @@ class JitsiMeetMethods {
onConferenceTerminated: (url, error) {
debugPrint("onConferenceTerminated: url: $url, error: $error");
if (timer != null) timer!.cancel();

Fluttertoast.cancel();
},
onAudioMutedChanged: (isMuted) {
Expand Down Expand Up @@ -120,6 +124,7 @@ class JitsiMeetMethods {
onClosed: () {
debugPrint("onClosed");
if (timer != null) timer!.cancel();

Fluttertoast.cancel();
},
),
Expand Down
20 changes: 17 additions & 3 deletions lib/data/data_sources/remote/auth/auth_api_service.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import 'package:dio/dio.dart' hide Headers;
import 'package:let_tutor/core/utils/constants.dart';
import 'package:let_tutor/data/models/auth/auth_model.dart';
import 'package:retrofit/retrofit.dart';

part 'auth_api_service.g.dart';

@RestApi(baseUrl: AppConstants.baseUrl)
@RestApi()
abstract class AuthApiService {
factory AuthApiService(Dio dio) = _AuthApiService;

Expand Down Expand Up @@ -48,8 +47,23 @@ abstract class AuthApiService {
'Content-Type': 'application/json',
})
Future<HttpResponse<String>> changePassword({
@Header('Authorization') required String token,
@Field("password") required String password,
@Field("newPassword") required String newPassword,
});

@POST('/auth/google')
@Headers(<String, dynamic>{
'Content-Type': 'application/json',
})
Future<HttpResponse<AuthModel>> loginGoogle({
@Field("access_token") required String accessToken,
});

@POST('/auth/facebook')
@Headers(<String, dynamic>{
'Content-Type': 'application/json',
})
Future<HttpResponse<AuthModel>> loginFacebook({
@Field("access_token") required String accessToken,
});
}
74 changes: 66 additions & 8 deletions lib/data/data_sources/remote/auth/auth_api_service.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions lib/data/data_sources/remote/course/course_api_service.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import 'package:dio/dio.dart' hide Headers;
import 'package:let_tutor/core/utils/constants.dart';
import 'package:let_tutor/data/models/course/course_model.dart';
import 'package:retrofit/retrofit.dart';

part 'course_api_service.g.dart';

@RestApi(baseUrl: AppConstants.baseUrl)
@RestApi()
abstract class CourseApiService {
factory CourseApiService(Dio dio) = _CourseApiService;

Expand All @@ -14,8 +13,12 @@ abstract class CourseApiService {
'Content-Type': 'application/json',
})
Future<HttpResponse<List<CourseModel>>> getListCourses({
@Header('Authorization') required String token,
@Query('page') required int page,
@Query('size') required int size,
@Query('level') List<int>? level,
@Query('order') String? order,
@Query('orderBy') String? orderBy,
@Query('categoryId') List<String>? categoryId,
@Query('q') String? q,
});
}
Loading

0 comments on commit 0b8d307

Please sign in to comment.