add device info at login
This commit is contained in:
parent
9b6e9c591d
commit
a4a12c6763
@ -4,6 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../common/utils/device_info_service.dart';
|
||||
import '../../../common/utils/fcm_service.dart';
|
||||
import '../../../domain/auth/auth.dart';
|
||||
|
||||
part 'login_form_event.dart';
|
||||
@ -13,7 +15,11 @@ part 'login_form_bloc.freezed.dart';
|
||||
@injectable
|
||||
class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
|
||||
final IAuthRepository _repository;
|
||||
LoginFormBloc(this._repository) : super(LoginFormState.initial()) {
|
||||
final DeviceInfoService _deviceInfoService;
|
||||
final FcmService _fcmService;
|
||||
|
||||
LoginFormBloc(this._repository, this._deviceInfoService, this._fcmService)
|
||||
: super(LoginFormState.initial()) {
|
||||
on<LoginFormEvent>(_onLoginFormEvent);
|
||||
}
|
||||
|
||||
@ -36,9 +42,25 @@ class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
|
||||
final passwordValid = state.password.isNotEmpty;
|
||||
|
||||
if (emailValid && passwordValid) {
|
||||
// Ambil device info dan FCM token secara paralel
|
||||
final results = await Future.wait([
|
||||
_deviceInfoService.getDeviceInfo(),
|
||||
_fcmService.getToken(),
|
||||
]);
|
||||
|
||||
final deviceInfo = results[0] as DeviceInfo;
|
||||
final fcmToken = results[1] as String?;
|
||||
|
||||
failureOrAuth = await _repository.login(
|
||||
email: state.email,
|
||||
password: state.password,
|
||||
deviceId: deviceInfo.deviceId,
|
||||
deviceName: deviceInfo.deviceName,
|
||||
deviceType: deviceInfo.deviceType,
|
||||
platform: deviceInfo.platform,
|
||||
osVersion: deviceInfo.osVersion,
|
||||
appVersion: deviceInfo.appVersion,
|
||||
fcmToken: fcmToken,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
|
||||
82
lib/common/utils/device_info_service.dart
Normal file
82
lib/common/utils/device_info_service.dart
Normal file
@ -0,0 +1,82 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class DeviceInfo {
|
||||
final String deviceId;
|
||||
final String deviceName;
|
||||
final String deviceType;
|
||||
final String platform;
|
||||
final String osVersion;
|
||||
final String appVersion;
|
||||
|
||||
const DeviceInfo({
|
||||
required this.deviceId,
|
||||
required this.deviceName,
|
||||
required this.deviceType,
|
||||
required this.platform,
|
||||
required this.osVersion,
|
||||
required this.appVersion,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'device_id': deviceId,
|
||||
'device_name': deviceName,
|
||||
'device_type': deviceType,
|
||||
'platform': platform,
|
||||
'os_version': osVersion,
|
||||
'app_version': appVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@lazySingleton
|
||||
class DeviceInfoService {
|
||||
final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin();
|
||||
|
||||
Future<DeviceInfo> getDeviceInfo() async {
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
final appVersion = packageInfo.version;
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final info = await _deviceInfo.androidInfo;
|
||||
return DeviceInfo(
|
||||
deviceId: info.id,
|
||||
deviceName: '${info.manufacturer} ${info.model}',
|
||||
deviceType: _resolveDeviceType(info.model),
|
||||
platform: 'android',
|
||||
osVersion: 'Android ${info.version.release}',
|
||||
appVersion: appVersion,
|
||||
);
|
||||
} else if (Platform.isIOS) {
|
||||
final info = await _deviceInfo.iosInfo;
|
||||
return DeviceInfo(
|
||||
deviceId: info.identifierForVendor ?? '',
|
||||
deviceName: info.name,
|
||||
deviceType: _resolveDeviceType(info.model),
|
||||
platform: 'ios',
|
||||
osVersion: '${info.systemName} ${info.systemVersion}',
|
||||
appVersion: appVersion,
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback (web/desktop — tidak dipakai tapi aman)
|
||||
return DeviceInfo(
|
||||
deviceId: 'unknown',
|
||||
deviceName: 'unknown',
|
||||
deviceType: 'desktop',
|
||||
platform: 'web',
|
||||
osVersion: 'unknown',
|
||||
appVersion: appVersion,
|
||||
);
|
||||
}
|
||||
|
||||
/// Tentukan device_type berdasarkan model name.
|
||||
/// Nilai valid: 'mobile' | 'tablet' | 'desktop'
|
||||
String _resolveDeviceType(String model) {
|
||||
final lower = model.toLowerCase();
|
||||
if (lower.contains('ipad') || lower.contains('tablet')) return 'tablet';
|
||||
return 'mobile';
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,13 @@ abstract class IAuthRepository {
|
||||
Future<Either<AuthFailure, Auth>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required String deviceId,
|
||||
required String deviceName,
|
||||
required String deviceType,
|
||||
required String platform,
|
||||
required String osVersion,
|
||||
required String appVersion,
|
||||
String? fcmToken,
|
||||
});
|
||||
Future<bool> hasToken();
|
||||
Future<Either<AuthFailure, User>> currentUser();
|
||||
|
||||
@ -21,11 +21,28 @@ class AuthRemoteDataProvider {
|
||||
Future<DC<AuthFailure, AuthDto>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required String deviceId,
|
||||
required String deviceName,
|
||||
required String deviceType,
|
||||
required String platform,
|
||||
required String osVersion,
|
||||
required String appVersion,
|
||||
String? fcmToken,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.post(
|
||||
ApiPath.login,
|
||||
data: {'email': email, 'password': password},
|
||||
data: {
|
||||
'email': email,
|
||||
'password': password,
|
||||
'device_id': deviceId,
|
||||
'device_name': deviceName,
|
||||
'device_type': deviceType,
|
||||
'platform': platform,
|
||||
'os_version': osVersion,
|
||||
'app_version': appVersion,
|
||||
if (fcmToken != null) 'fcm_token': fcmToken,
|
||||
},
|
||||
);
|
||||
|
||||
if (response.data['code'] == 401) {
|
||||
|
||||
@ -21,11 +21,25 @@ class AuthRepository implements IAuthRepository {
|
||||
Future<Either<AuthFailure, Auth>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required String deviceId,
|
||||
required String deviceName,
|
||||
required String deviceType,
|
||||
required String platform,
|
||||
required String osVersion,
|
||||
required String appVersion,
|
||||
String? fcmToken,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _remoteDataProvider.login(
|
||||
email: email,
|
||||
password: password,
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
deviceType: deviceType,
|
||||
platform: platform,
|
||||
osVersion: osVersion,
|
||||
appVersion: appVersion,
|
||||
fcmToken: fcmToken,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
|
||||
@ -59,6 +59,8 @@ import 'package:apskel_owner_flutter/common/di/di_shared_preferences.dart'
|
||||
as _i402;
|
||||
import 'package:apskel_owner_flutter/common/network/network_client.dart'
|
||||
as _i543;
|
||||
import 'package:apskel_owner_flutter/common/utils/device_info_service.dart'
|
||||
as _i902;
|
||||
import 'package:apskel_owner_flutter/common/utils/fcm_service.dart' as _i179;
|
||||
import 'package:apskel_owner_flutter/domain/analytic/repositories/i_analytic_repository.dart'
|
||||
as _i477;
|
||||
@ -146,6 +148,7 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
preResolve: true,
|
||||
);
|
||||
gh.lazySingleton<_i179.FcmService>(() => _i179.FcmService());
|
||||
gh.lazySingleton<_i902.DeviceInfoService>(() => _i902.DeviceInfoService());
|
||||
gh.lazySingleton<_i543.NetworkClient>(
|
||||
() => _i543.NetworkClient(gh<_i895.Connectivity>()),
|
||||
);
|
||||
@ -261,9 +264,6 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i945.AuthBloc>(
|
||||
() => _i945.AuthBloc(gh<_i49.IAuthRepository>()),
|
||||
);
|
||||
gh.factory<_i775.LoginFormBloc>(
|
||||
() => _i775.LoginFormBloc(gh<_i49.IAuthRepository>()),
|
||||
);
|
||||
gh.factory<_i574.LogoutFormBloc>(
|
||||
() => _i574.LogoutFormBloc(gh<_i49.IAuthRepository>()),
|
||||
);
|
||||
@ -276,6 +276,13 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i147.UserEditFormBloc>(
|
||||
() => _i147.UserEditFormBloc(gh<_i635.IUserRepository>()),
|
||||
);
|
||||
gh.factory<_i775.LoginFormBloc>(
|
||||
() => _i775.LoginFormBloc(
|
||||
gh<_i49.IAuthRepository>(),
|
||||
gh<_i902.DeviceInfoService>(),
|
||||
gh<_i179.FcmService>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i346.InventoryReportBloc>(
|
||||
() => _i346.InventoryReportBloc(
|
||||
gh<_i477.IAnalyticRepository>(),
|
||||
|
||||
@ -14,11 +14,15 @@ import 'package:flutter/widgets.dart';
|
||||
class $AssetsImagesGen {
|
||||
const $AssetsImagesGen();
|
||||
|
||||
/// File path: assets/images/ic_notification.png
|
||||
AssetGenImage get icNotification =>
|
||||
const AssetGenImage('assets/images/ic_notification.png');
|
||||
|
||||
/// File path: assets/images/logo.png
|
||||
AssetGenImage get logo => const AssetGenImage('assets/images/logo.png');
|
||||
|
||||
/// List of all assets
|
||||
List<AssetGenImage> get values => [logo];
|
||||
List<AssetGenImage> get values => [icNotification, logo];
|
||||
}
|
||||
|
||||
class Assets {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user