relatica/lib/services/auth_service.dart

191 wiersze
5.7 KiB
Dart

import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:result_monad/result_monad.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../di_initialization.dart';
import '../friendica_client/friendica_client.dart';
import '../globals.dart';
import '../models/auth/credentials_intf.dart';
import '../models/auth/profile.dart';
import '../models/exec_error.dart';
import '../update_timer_initialization.dart';
import 'secrets_service.dart';
import 'status_service.dart';
class AccountsService extends ChangeNotifier {
static final _logger = Logger('$AccountsService');
Profile? _currentProfile;
final _loggedInProfiles = <Profile>{};
final _loggedOutProfiles = <Profile>{};
var _initializing = false;
final SecretsService secretsService;
AccountsService(this.secretsService);
bool get loggedIn => _currentProfile != null;
bool get initializing => _initializing;
List<Profile> get loggedInProfiles => UnmodifiableListView(_loggedInProfiles);
List<Profile> get loggedOutProfiles =>
UnmodifiableListView(_loggedOutProfiles);
Profile get currentProfile => _currentProfile!;
FutureResult<bool, ExecError> initialize() async {
final lastActiveProfile = await _getStoredLoginState();
_initializing = true;
final result = await runCatchingAsync(() async {
final initialProfiles = secretsService.profiles;
for (final p in initialProfiles) {
if (!p.loggedIn) {
_loggedOutProfiles.add(p);
continue;
}
final pr = await signIn(p.credentials, withNotification: false);
if (pr.isSuccess) {
final profile = pr.value;
if (profile.id.isNotEmpty && profile.id == lastActiveProfile) {
_currentProfile = profile;
Future.delayed(
const Duration(seconds: 10),
() async => await executeUpdatesForProfile(profile),
);
}
} else {
await signOut(p, withNotification: false);
}
}
if (_currentProfile == null && _loggedInProfiles.isNotEmpty) {
await setActiveProfile(_loggedInProfiles.first);
}
notifyListeners();
return Result.ok(loggedIn);
});
_initializing = false;
return result.execErrorCast();
}
FutureResult<Profile, ExecError> signIn(ICredentials credentials,
{bool withNotification = true}) async {
ICredentials? credentialsCache;
final result =
await credentials.signIn().andThenAsync((signedInCredentials) async {
final client =
ProfileClient(Profile.credentialsOnly(signedInCredentials));
credentialsCache = signedInCredentials;
getIt<StatusService>().setStatus(
'Getting user profile from ${signedInCredentials.serverName}');
return await client.getMyProfile();
}).andThenAsync((profileData) async {
final loginProfile = Profile(
credentials: credentialsCache!,
username: profileData.name,
serverName: credentialsCache!.serverName,
avatar: profileData.avatarUrl,
userId: profileData.id,
loggedIn: true,
);
getIt<StatusService>()
.setStatus('Loaded user profile ${profileData.handle}');
if (_loggedInProfiles.isEmpty) {
await setActiveProfile(loginProfile,
withNotification: withNotification);
}
_loggedInProfiles.add(loginProfile);
_loggedOutProfiles.remove(loginProfile);
await secretsService.addOrUpdateProfile(loginProfile);
await updateProfileDependencyInjectors(loginProfile);
if (withNotification) {
notifyListeners();
}
return Result.ok(loginProfile);
});
if (result.isFailure) {
getIt<StatusService>().setStatus('Error signing in: ${result.error}');
_logger.severe('Error signing in: ${result.error}');
}
return result.execErrorCast();
}
Future signOut(Profile profile, {bool withNotification = true}) async {
if (_currentProfile == profile) {
await clearActiveProfile(withNotification: withNotification);
}
_loggedInProfiles.remove(profile);
_loggedOutProfiles.add(profile.copyWithLoginUpdate(false));
await secretsService.addOrUpdateProfile(profile.copyWithLoginUpdate(false));
if (_loggedInProfiles.isNotEmpty) {
setActiveProfile(
_loggedInProfiles.first,
withNotification: withNotification,
);
}
if (withNotification) {
notifyListeners();
}
}
Future removeProfile(Profile profile, {bool withNotification = true}) async {
if (_currentProfile == profile) {
await clearActiveProfile(withNotification: withNotification);
}
_loggedInProfiles.remove(profile);
_loggedOutProfiles.remove(profile);
await secretsService.removeProfile(profile);
if (_loggedInProfiles.isNotEmpty) {
setActiveProfile(
_loggedInProfiles.first,
withNotification: withNotification,
);
}
if (withNotification) {
notifyListeners();
}
}
Future clearActiveProfile({bool withNotification = true}) async {
_currentProfile = null;
if (withNotification) {
notifyListeners();
}
await _saveStoredLoginState();
}
Future<void> setActiveProfile(Profile profile,
{bool withNotification = true}) async {
_currentProfile = profile;
if (withNotification) {
notifyListeners();
}
await _saveStoredLoginState();
}
Future<void> _saveStoredLoginState() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('active_profile_id', _currentProfile?.id ?? '');
}
Future<String> _getStoredLoginState() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('active_profile_id') ?? '';
}
}