Skip to content

Commit 8a0a3a4

Browse files
authored
Merge pull request #568 from DevKor-github/feature/issue-528-core-service-dependencies
Refactor core service dependencies
2 parents 3f1811c + 0eb5fdd commit 8a0a3a4

14 files changed

Lines changed: 345 additions & 262 deletions

lib/core/dio/app_dio.dart

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,39 @@ import 'package:on_time_front/core/constants/environment_variable.dart';
44
import 'package:on_time_front/core/dio/adapters/shared.dart';
55
import 'package:on_time_front/core/dio/interceptors/logger_interceptor.dart';
66
import 'package:on_time_front/core/dio/interceptors/token_interceptor.dart';
7+
import 'package:on_time_front/core/dio/interceptors/token_session_invalidator.dart';
78
import 'package:on_time_front/core/dio/transformers/logging_transformer.dart';
9+
import 'package:on_time_front/data/data_sources/token_local_data_source.dart';
810

911
@Injectable(as: Dio)
1012
class AppDio with DioMixin implements Dio {
11-
AppDio() {
13+
AppDio(
14+
TokenLocalDataSource tokenLocalDataSource,
15+
TokenSessionInvalidator sessionInvalidator,
16+
) {
1217
httpClientAdapter = getAdapter();
1318
transformer = LoggingTransformer(inner: BackgroundTransformer());
1419
options = BaseOptions(
15-
contentType: Headers.jsonContentType,
16-
baseUrl: EnvironmentVariable.restApiUrl,
17-
connectTimeout: const Duration(milliseconds: 30000),
18-
receiveTimeout: const Duration(milliseconds: 30000),
19-
sendTimeout: const Duration(milliseconds: 30000),
20-
receiveDataWhenStatusError: true,
21-
followRedirects: false,
22-
headers: {
23-
"Accept": "application/json",
24-
"Authorization": EnvironmentVariable.restAuthToken
25-
});
20+
contentType: Headers.jsonContentType,
21+
baseUrl: EnvironmentVariable.restApiUrl,
22+
connectTimeout: const Duration(milliseconds: 30000),
23+
receiveTimeout: const Duration(milliseconds: 30000),
24+
sendTimeout: const Duration(milliseconds: 30000),
25+
receiveDataWhenStatusError: true,
26+
followRedirects: false,
27+
headers: {
28+
"Accept": "application/json",
29+
"Authorization": EnvironmentVariable.restAuthToken,
30+
},
31+
);
2632

27-
interceptors.addAll([TokenInterceptor(this), LoggerInterceptor()]);
33+
interceptors.addAll([
34+
TokenInterceptor(
35+
this,
36+
tokenLocalDataSource: tokenLocalDataSource,
37+
sessionInvalidator: sessionInvalidator,
38+
),
39+
LoggerInterceptor(),
40+
]);
2841
}
2942
}

lib/core/dio/interceptors/token_interceptor.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import 'package:dio/dio.dart';
22
import 'package:on_time_front/core/constants/endpoint.dart';
3-
import 'package:on_time_front/core/di/di_setup.dart';
3+
import 'package:on_time_front/core/dio/interceptors/token_session_invalidator.dart';
44
import 'package:on_time_front/core/logging/app_logger.dart';
55
import 'package:on_time_front/data/data_sources/token_local_data_source.dart';
66
import 'package:on_time_front/domain/entities/token_entity.dart';
7-
import 'package:on_time_front/domain/repositories/user_repository.dart';
87

98
class TokenInterceptor implements InterceptorsWrapper {
109
static const _refreshTokenPath = '/refresh-token';
@@ -13,9 +12,14 @@ class TokenInterceptor implements InterceptorsWrapper {
1312
'Authentication token is unavailable for a protected request';
1413

1514
final Dio dio;
16-
TokenInterceptor(this.dio);
17-
final TokenLocalDataSource tokenLocalDataSource = getIt
18-
.get<TokenLocalDataSource>();
15+
final TokenLocalDataSource tokenLocalDataSource;
16+
final TokenSessionInvalidator _sessionInvalidator;
17+
18+
TokenInterceptor(
19+
this.dio, {
20+
required this.tokenLocalDataSource,
21+
required TokenSessionInvalidator sessionInvalidator,
22+
}) : _sessionInvalidator = sessionInvalidator;
1923

2024
// when accessToken is expired & having multiple requests call
2125
// this variable to lock others request to make sure only trigger call refresh token 01 times
@@ -186,11 +190,7 @@ class TokenInterceptor implements InterceptorsWrapper {
186190
}
187191

188192
Future<void> _signOutLocally() async {
189-
try {
190-
await getIt.get<UserRepository>().signOut();
191-
} catch (_) {
192-
await tokenLocalDataSource.deleteToken();
193-
}
193+
await _sessionInvalidator.signOutLocally();
194194
}
195195

196196
@override
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
abstract interface class TokenSessionInvalidator {
2+
Future<void> signOutLocally();
3+
}

lib/core/services/notification_service.dart

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ import 'package:firebase_core/firebase_core.dart';
88

99
import 'package:firebase_messaging/firebase_messaging.dart';
1010
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
11-
import 'package:on_time_front/core/di/di_setup.dart';
1211
import 'package:on_time_front/core/logging/app_logger.dart';
1312
import 'package:on_time_front/core/services/js_interop_service.dart';
14-
import 'package:on_time_front/core/services/navigation_service.dart';
1513
import 'package:on_time_front/core/services/notification_content.dart';
1614
import 'package:on_time_front/core/services/notification_routing.dart';
17-
import 'package:on_time_front/data/data_sources/notification_remote_data_source.dart';
18-
import 'package:on_time_front/data/models/fcm_token_register_request_model.dart';
15+
import 'package:on_time_front/core/services/notification_tap_router.dart';
16+
import 'package:on_time_front/core/services/notification_token_registrar.dart';
1917
import 'package:on_time_front/domain/entities/alarm_entities.dart';
20-
import 'package:on_time_front/domain/repositories/alarm_repository.dart';
2118
import 'package:permission_handler/permission_handler.dart'
2219
as permission_handler;
2320
import 'package:timezone/data/latest.dart' as tz_data;
@@ -43,13 +40,18 @@ class NotificationService {
4340
FlutterLocalNotificationsPlugin? localNotifications,
4441
String Function()? localeProvider,
4542
bool? isIOSOverride,
43+
FcmTokenRegistrar? fcmTokenRegistrar,
44+
NotificationTapRouter? notificationTapRouter,
4645
Stream<RemoteMessage>? onMessage,
4746
Stream<RemoteMessage>? onMessageOpenedApp,
4847
}) : _messaging = messaging ?? FirebaseMessaging.instance,
4948
_localNotifications =
5049
localNotifications ?? FlutterLocalNotificationsPlugin(),
5150
_localeProvider = localeProvider,
5251
_isIOSOverride = isIOSOverride,
52+
_fcmTokenRegistrar = fcmTokenRegistrar ?? const NoopFcmTokenRegistrar(),
53+
_notificationTapRouter =
54+
notificationTapRouter ?? const NoopNotificationTapRouter(),
5355
_onMessage = onMessage ?? FirebaseMessaging.onMessage,
5456
_onMessageOpenedApp =
5557
onMessageOpenedApp ?? FirebaseMessaging.onMessageOpenedApp;
@@ -62,12 +64,17 @@ class NotificationService {
6264
bool isFlutterLocalNotificationsInitialized = false,
6365
bool isTimezoneInitialized = false,
6466
bool? isIOSOverride,
67+
FcmTokenRegistrar? fcmTokenRegistrar,
68+
NotificationTapRouter? notificationTapRouter,
6569
Stream<RemoteMessage>? onMessage,
6670
Stream<RemoteMessage>? onMessageOpenedApp,
6771
}) : _messaging = messaging,
6872
_localNotifications = localNotifications,
6973
_localeProvider = localeProvider,
7074
_isIOSOverride = isIOSOverride,
75+
_fcmTokenRegistrar = fcmTokenRegistrar ?? const NoopFcmTokenRegistrar(),
76+
_notificationTapRouter =
77+
notificationTapRouter ?? const NoopNotificationTapRouter(),
7178
_onMessage = onMessage ?? FirebaseMessaging.onMessage,
7279
_onMessageOpenedApp =
7380
onMessageOpenedApp ?? FirebaseMessaging.onMessageOpenedApp,
@@ -84,6 +91,8 @@ class NotificationService {
8491
final FlutterLocalNotificationsPlugin _localNotifications;
8592
final String Function()? _localeProvider;
8693
final bool? _isIOSOverride;
94+
FcmTokenRegistrar _fcmTokenRegistrar;
95+
NotificationTapRouter _notificationTapRouter;
8796
final Stream<RemoteMessage> _onMessage;
8897
final Stream<RemoteMessage> _onMessageOpenedApp;
8998
bool _isFlutterLocalNotificationsInitialized = false;
@@ -110,6 +119,14 @@ class NotificationService {
110119
}
111120
}
112121

122+
void configureDelegates({
123+
required FcmTokenRegistrar fcmTokenRegistrar,
124+
required NotificationTapRouter notificationTapRouter,
125+
}) {
126+
_fcmTokenRegistrar = fcmTokenRegistrar;
127+
_notificationTapRouter = notificationTapRouter;
128+
}
129+
113130
Future<void> initialize() {
114131
if (_isInitialized) {
115132
return Future.value();
@@ -255,13 +272,7 @@ class NotificationService {
255272

256273
if (token != null) {
257274
try {
258-
final deviceId = await getIt.get<AlarmRepository>().getDeviceId();
259-
await getIt.get<NotificationRemoteDataSource>().fcmTokenRegister(
260-
FcmTokenRegisterRequestModel(
261-
firebaseToken: token,
262-
deviceId: deviceId,
263-
),
264-
);
275+
await _fcmTokenRegistrar.registerToken(token);
265276
AppLogger.debug('[FCM] FCM Token 서버 등록 완료');
266277
} catch (e) {
267278
AppLogger.debug('[FCM] FCM Token 서버 등록 실패: $e');
@@ -274,12 +285,9 @@ class NotificationService {
274285
AppLogger.debug(
275286
'[FCM] token refreshed token=${AppLogger.redactToken(newToken)}',
276287
);
277-
getIt.get<AlarmRepository>().getDeviceId().then((deviceId) {
278-
getIt.get<NotificationRemoteDataSource>().fcmTokenRegister(
279-
FcmTokenRegisterRequestModel(
280-
firebaseToken: newToken,
281-
deviceId: deviceId,
282-
),
288+
_fcmTokenRegistrar.registerToken(newToken).catchError((e) {
289+
AppLogger.debug(
290+
'[FCM] refreshed token server registration failed: $e',
283291
);
284292
});
285293
});
@@ -679,18 +687,11 @@ class NotificationService {
679687

680688
void _handleLocalNotificationTap(String? payload) {
681689
AppLogger.debug('[FCM] 알림 탭');
682-
final target = notificationRouteForPayloadString(payload);
683-
if (target != null) {
684-
getIt.get<NavigationService>().push(target.path, extra: target.extra);
685-
}
690+
_notificationTapRouter.routeLocalNotificationTap(payload);
686691
}
687692

688693
Future<void> _handleBackgroundMessage(RemoteMessage message) async {
689694
AppLogger.debug('[FCM] 백그라운드 메시지 처리');
690-
691-
final target = notificationRouteForData(message.data);
692-
if (target != null) {
693-
getIt.get<NavigationService>().push(target.path, extra: target.extra);
694-
}
695+
_notificationTapRouter.routeRemoteNotificationData(message.data);
695696
}
696697
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:injectable/injectable.dart';
2+
import 'package:on_time_front/core/services/navigation_service.dart';
3+
import 'package:on_time_front/core/services/notification_routing.dart';
4+
5+
abstract interface class NotificationTapRouter {
6+
void routeLocalNotificationTap(String? payload);
7+
8+
void routeRemoteNotificationData(Map<dynamic, dynamic> data);
9+
}
10+
11+
class NoopNotificationTapRouter implements NotificationTapRouter {
12+
const NoopNotificationTapRouter();
13+
14+
@override
15+
void routeLocalNotificationTap(String? payload) {}
16+
17+
@override
18+
void routeRemoteNotificationData(Map<dynamic, dynamic> data) {}
19+
}
20+
21+
@Singleton(as: NotificationTapRouter)
22+
class NavigationNotificationTapRouter implements NotificationTapRouter {
23+
NavigationNotificationTapRouter(this._navigationService);
24+
25+
final NavigationService _navigationService;
26+
27+
@override
28+
void routeLocalNotificationTap(String? payload) {
29+
final target = notificationRouteForPayloadString(payload);
30+
_pushTarget(target);
31+
}
32+
33+
@override
34+
void routeRemoteNotificationData(Map<dynamic, dynamic> data) {
35+
final target = notificationRouteForData(data);
36+
_pushTarget(target);
37+
}
38+
39+
void _pushTarget(NotificationRouteTarget? target) {
40+
if (target == null) return;
41+
_navigationService.push(target.path, extra: target.extra);
42+
}
43+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
abstract interface class FcmTokenRegistrar {
2+
Future<void> registerToken(String firebaseToken);
3+
}
4+
5+
class NoopFcmTokenRegistrar implements FcmTokenRegistrar {
6+
const NoopFcmTokenRegistrar();
7+
8+
@override
9+
Future<void> registerToken(String firebaseToken) async {}
10+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import 'package:injectable/injectable.dart';
2+
import 'package:on_time_front/core/services/notification_token_registrar.dart';
3+
import 'package:on_time_front/data/data_sources/notification_remote_data_source.dart';
4+
import 'package:on_time_front/data/models/fcm_token_register_request_model.dart';
5+
import 'package:on_time_front/domain/repositories/alarm_repository.dart';
6+
7+
@Singleton(as: FcmTokenRegistrar)
8+
class DeviceFcmTokenRegistrar implements FcmTokenRegistrar {
9+
DeviceFcmTokenRegistrar(
10+
this._alarmRepository,
11+
this._notificationRemoteDataSource,
12+
);
13+
14+
final AlarmRepository _alarmRepository;
15+
final NotificationRemoteDataSource _notificationRemoteDataSource;
16+
17+
@override
18+
Future<void> registerToken(String firebaseToken) async {
19+
final deviceId = await _alarmRepository.getDeviceId();
20+
await _notificationRemoteDataSource.fcmTokenRegister(
21+
FcmTokenRegisterRequestModel(
22+
firebaseToken: firebaseToken,
23+
deviceId: deviceId,
24+
),
25+
);
26+
}
27+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import 'package:injectable/injectable.dart';
2+
import 'package:on_time_front/core/dio/interceptors/token_session_invalidator.dart';
3+
import 'package:on_time_front/data/data_sources/token_local_data_source.dart';
4+
5+
@Singleton(as: TokenSessionInvalidator)
6+
class TokenLocalSessionInvalidator implements TokenSessionInvalidator {
7+
TokenLocalSessionInvalidator(this._tokenLocalDataSource);
8+
9+
final TokenLocalDataSource _tokenLocalDataSource;
10+
11+
@override
12+
Future<void> signOutLocally() {
13+
return _tokenLocalDataSource.deleteToken();
14+
}
15+
}

lib/main.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import 'package:intl/date_symbol_data_local.dart';
55
import 'package:on_time_front/core/di/di_setup.dart';
66
import 'package:on_time_front/core/logging/app_logger.dart';
77
import 'package:on_time_front/core/services/device_info_service/shared.dart';
8+
import 'package:on_time_front/core/services/notification_service.dart';
9+
import 'package:on_time_front/core/services/notification_tap_router.dart';
10+
import 'package:on_time_front/core/services/notification_token_registrar.dart';
811
import 'package:on_time_front/firebase_options.dart';
912
import 'package:on_time_front/presentation/app/screens/app.dart';
1013

@@ -13,11 +16,13 @@ void main() async {
1316
AppLogger.configureFlutterDebugPrint();
1417
await HardwareKeyboard.instance.syncKeyboardState().catchError((_) {});
1518
await initializeDateFormatting();
16-
await Firebase.initializeApp(
17-
options: DefaultFirebaseOptions.currentPlatform,
18-
);
19+
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
1920
AppLogger.debug('[FCM Main] Firebase initialized');
2021
configureDependencies();
22+
NotificationService.instance.configureDelegates(
23+
fcmTokenRegistrar: getIt.get<FcmTokenRegistrar>(),
24+
notificationTapRouter: getIt.get<NotificationTapRouter>(),
25+
);
2126

2227
AppLogger.debug(
2328
'Device standalone mode=${DeviceInfoService.isInStandaloneMode}',

0 commit comments

Comments
 (0)