diff --git a/lib/friendica_client/friendica_client.dart b/lib/friendica_client/friendica_client.dart index b3a98ef..f72d85f 100644 --- a/lib/friendica_client/friendica_client.dart +++ b/lib/friendica_client/friendica_client.dart @@ -779,18 +779,21 @@ class ProfileClient extends FriendicaClient { ProfileClient(super.credentials) : super(); - FutureResult getMyProfile() async { + FutureResult<(Connection, Profile), ExecError> getMyProfile() async { _logger.finest(() => 'Getting logged in user profile'); final request = Uri.parse('https://$serverName/api/v1/accounts/verify_credentials'); return (await _getApiRequest(request, timeout: oauthTimeout)) - .mapValue((json) => ConnectionMastodonExtensions.fromJson( - json, - defaultServerName: serverName, - ).copy( - status: ConnectionStatus.you, - network: 'friendica', - )); + .mapValue((json) { + final connection = ConnectionMastodonExtensions.fromJson( + json, + defaultServerName: serverName, + ).copy( + status: ConnectionStatus.you, + network: 'friendica', + ); + return (connection, profile); + }); } } diff --git a/lib/models/auth/basic_credentials.dart b/lib/models/auth/basic_credentials.dart index 700d74e..8cc4430 100644 --- a/lib/models/auth/basic_credentials.dart +++ b/lib/models/auth/basic_credentials.dart @@ -52,6 +52,7 @@ class BasicCredentials implements ICredentials { String? serverName, }) { return BasicCredentials( + id: id, username: username ?? this.username, password: password ?? this.password, serverName: serverName ?? this.serverName, diff --git a/lib/screens/sign_in.dart b/lib/screens/sign_in.dart index 8fd4153..762c291 100644 --- a/lib/screens/sign_in.dart +++ b/lib/screens/sign_in.dart @@ -373,6 +373,20 @@ class _SignInScreenState extends State { }).toList(), ), ), + const VerticalPadding(), + ElevatedButton( + onPressed: () async { + final confirm = await showYesNoDialog(context, + 'Are you sure you want to logout and delete *all* accounts? This cannot be undone.') ?? + false; + print(confirm); + if (!confirm) { + return; + } + + await getIt().clearAllProfiles(); + }, + child: Text('Clear All')), ], ), ), @@ -395,8 +409,9 @@ class _SignInScreenState extends State { } else { switch (authType) { case usernamePasswordType: + final username = usernameController.text.split('@').first; creds = BasicCredentials( - username: usernameController.text, + username: username, password: passwordController.text, serverName: serverNameController.text); break; diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 891f01a..b4a607c 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -78,20 +78,20 @@ class AccountsService extends ChangeNotifier { FutureResult 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().setStatus( 'Getting user profile from ${signedInCredentials.serverName}'); return await client.getMyProfile(); - }).andThenAsync((profileData) async { + }).andThenAsync((profileResult) async { + final profileData = profileResult.$1; + final profile = profileResult.$2; final loginProfile = Profile( - credentials: credentialsCache!, + credentials: profile.credentials, username: profileData.name, - serverName: credentialsCache!.serverName, + serverName: profile.credentials.serverName, avatar: profileData.avatarUrl, userId: profileData.id, loggedIn: true, @@ -178,6 +178,14 @@ class AccountsService extends ChangeNotifier { await _saveStoredLoginState(); } + Future clearAllProfiles() async { + _loggedInProfiles.clear(); + _loggedOutProfiles.clear(); + _currentProfile = null; + await secretsService.clearCredentials(); + notifyListeners(); + } + Future _saveStoredLoginState() async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('active_profile_id', _currentProfile?.id ?? ''); diff --git a/lib/services/secrets_service.dart b/lib/services/secrets_service.dart index 8fc05ae..c76ff2a 100644 --- a/lib/services/secrets_service.dart +++ b/lib/services/secrets_service.dart @@ -41,6 +41,7 @@ class SecretsService { try { await _secureStorage.delete(key: _basicProfilesKey); await _secureStorage.delete(key: _oauthProfilesKey); + profiles.clear(); return Result.ok(profiles); } catch (e) { return Result.error(ExecError( diff --git a/lib/utils/network_utils.dart b/lib/utils/network_utils.dart index 8fe36a7..60690f3 100644 --- a/lib/utils/network_utils.dart +++ b/lib/utils/network_utils.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; import 'package:logging/logging.dart'; import 'package:result_monad/result_monad.dart'; @@ -80,10 +81,16 @@ class _CachedResponse { other is _CachedResponse && runtimeType == other.runtimeType && requestType == other.requestType && - requestUri == other.requestUri; + requestUri == other.requestUri && + const MapEquality().equals(requestBody, other.requestBody) && + const MapEquality().equals(headers, other.headers); @override - int get hashCode => requestType.hashCode ^ requestUri.hashCode; + int get hashCode => + requestType.hashCode ^ + requestUri.hashCode ^ + const MapEquality().hash(requestBody) ^ + const MapEquality().hash(headers); } class _ExpiringRequestCache { @@ -121,7 +128,7 @@ class _ExpiringRequestCache { late final http.Response response; if (_responses.containsKey(requestStub)) { - print('Returning cached response for $type => $url'); + _logger.fine('Returning cached response for $type => $url'); response = _responses[requestStub]?.response ?? http.Response('', 555); } else { final request = RelaticaUserAgentHttpClient().get(