[READ ONLY MIRROR] Open Source TikTok alternative built on AT Protocol github.com/sprksocial/client
flutter atproto video dart
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix profile edit (#68)

authored by

Davi Rodrigues and committed by
GitHub
28ebd661 b7adcc8a

+36 -20
+2 -1
lib/src/core/network/atproto/data/repositories/actor_repository.dart
··· 1 + import 'package:atproto/core.dart'; 1 2 import 'package:sparksocial/src/core/network/atproto/data/models/actor_models.dart'; 2 3 3 4 /// Interface for Actor-related API endpoints ··· 17 18 /// [displayName] The new display name 18 19 /// [description] The new description 19 20 /// [avatar] The new avatar (optional) 20 - Future<void> updateProfile({required String displayName, required String description, dynamic avatar}); 21 + Future<void> updateProfile({required String displayName, required String description, Blob? avatar}); 21 22 22 23 /// Check if a user is an early supporter 23 24 ///
+4 -4
lib/src/core/network/atproto/data/repositories/actor_repository_impl.dart
··· 1 1 import 'dart:convert'; 2 2 3 3 import 'package:atproto/core.dart'; 4 - import 'package:bluesky/bluesky.dart'; 4 + import 'package:bluesky/bluesky.dart' as bsky; 5 5 import 'package:get_it/get_it.dart'; 6 6 import 'package:http/http.dart' as http; 7 + import 'package:sparksocial/src/core/network/atproto/data/models/models.dart'; 7 8 import 'package:sparksocial/src/core/network/atproto/data/repositories/actor_repository.dart'; 8 9 import 'package:sparksocial/src/core/utils/logging/log_service.dart'; 9 10 import 'package:sparksocial/src/core/network/atproto/data/repositories/sprk_repository.dart'; 10 - import 'package:sparksocial/src/core/network/atproto/data/models/actor_models.dart'; 11 11 12 12 /// Actor-related API endpoints implementation 13 13 class ActorRepositoryImpl implements ActorRepository { ··· 44 44 } catch (e) { 45 45 _logger.e('Failed to retrieve profile for DID: $did', error: e); 46 46 _logger.i('Trying to get profile from bluesky'); 47 - final bluesky = Bluesky.fromSession(_client.authRepository.session!); 47 + final bluesky = bsky.Bluesky.fromSession(_client.authRepository.session!); 48 48 final profile = await bluesky.actor.getProfile(actor: did); 49 49 _logger.d('Profile retrieved successfully from bluesky'); 50 50 return ProfileViewDetailed.fromJson(profile.toJson()); ··· 93 93 } 94 94 95 95 @override 96 - Future<void> updateProfile({required String displayName, required String description, dynamic avatar}) async { 96 + Future<void> updateProfile({required String displayName, required String description, Blob? avatar}) async { 97 97 if (!_client.authRepository.isAuthenticated) { 98 98 throw Exception('Not authenticated'); 99 99 }
+30 -15
lib/src/features/profile/providers/edit_profile_provider.dart
··· 70 70 71 71 state = state.copyWith(isSaving: true); 72 72 73 - dynamic avatarToSend; 73 + final atprotoClient = _authRepository.atproto; 74 + if (atprotoClient == null) { 75 + throw Exception('AtProto client not initialized'); 76 + } 77 + 78 + Blob? avatarToSend; 74 79 75 80 if (state.localAvatar is Uint8List) { 76 - // Upload new avatar blob 77 - final client = _authRepository.atproto!; 78 - final respBlob = await client.repo.uploadBlob(state.localAvatar as Uint8List); 81 + // A new avatar image was picked, upload it as a blob. 82 + final respBlob = await atprotoClient.repo.uploadBlob(state.localAvatar as Uint8List); 79 83 if (respBlob.status.code != 200) { 80 84 throw Exception('Failed to upload avatar blob'); 81 85 } 82 - avatarToSend = respBlob.data.blob.toJson(); 83 - } else if (state.localAvatar is String && state.localAvatar != state.initialAvatar) { 84 - // A string URL was passed that's different from initial - fetch existing record 86 + avatarToSend = respBlob.data.blob; 87 + } else if (state.localAvatar == null) { 88 + // If localAvatar is null, it means the avatar was cleared or never set. 89 + // Send null to remove any existing avatar from the profile. 90 + avatarToSend = null; 91 + } else { 92 + // If localAvatar is a String (and not null), it implies the avatar was not changed 93 + // and we need to maintain the existing one by fetching its Blob from the record. 94 + logger.d('Maintaining existing avatar from record ${state.profile.did}'); 85 95 final uri = AtUri.parse('at://${state.profile.did}/so.sprk.actor.profile/self'); 86 - final recRes = await _authRepository.atproto!.repo.getRecord(uri: uri); 96 + final recRes = await atprotoClient.repo.getRecord(uri: uri); 87 97 final recordData = recRes.data.value; 88 - avatarToSend = recordData['avatar']; 89 - } else if (state.initialAvatar != null) { 90 - // No change but avatar exists - maintain it 91 - final uri = AtUri.parse('at://${state.profile.did}/so.sprk.actor.profile/self'); 92 - final recRes = await _authRepository.atproto!.repo.getRecord(uri: uri); 93 - final recordData = recRes.data.value; 94 - avatarToSend = recordData['avatar']; 98 + 99 + // Ensure the 'avatar' field exists and is a Map before converting to Blob. 100 + // If it's null, it means the user had no avatar on the record. 101 + if (recordData['avatar'] is Map<String, dynamic>) { 102 + avatarToSend = Blob.fromJson(recordData['avatar']); 103 + logger.d('Blob avatar: $avatarToSend'); 104 + } else { 105 + // This case handles an inconsistency where localAvatar was a string (URL), 106 + // but the actual record on the server has no avatar. Set to null gracefully. 107 + logger.w('Local avatar was string, but record has no avatar. Setting avatarToSend to null.'); 108 + avatarToSend = null; 109 + } 95 110 } 96 111 97 112 await actorRepository.updateProfile(