Add new friends system, and sharing legs support
All checks were successful
Release / meta (push) Successful in 9s
Release / linux-build (push) Successful in 6m37s
Release / web-build (push) Successful in 5m29s
Release / android-build (push) Successful in 15m58s
Release / release-master (push) Successful in 20s
Release / release-dev (push) Successful in 26s
All checks were successful
Release / meta (push) Successful in 9s
Release / linux-build (push) Successful in 6m37s
Release / web-build (push) Successful in 5m29s
Release / android-build (push) Successful in 15m58s
Release / release-master (push) Successful in 20s
Release / release-dev (push) Successful in 26s
This commit is contained in:
282
lib/services/data_service/data_service_friendships.dart
Normal file
282
lib/services/data_service/data_service_friendships.dart
Normal file
@@ -0,0 +1,282 @@
|
||||
part of 'data_service.dart';
|
||||
|
||||
extension DataServiceFriendships on DataService {
|
||||
Future<void> fetchFriendships() async {
|
||||
_isFriendshipsLoading = true;
|
||||
try {
|
||||
final json = await api.get('/friendships');
|
||||
List<dynamic>? list;
|
||||
if (json is List) {
|
||||
list = json;
|
||||
} else if (json is Map) {
|
||||
for (final key in ['friendships', 'data', 'items', 'results']) {
|
||||
final value = json[key];
|
||||
if (value is List) {
|
||||
list = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final parsed = list
|
||||
?.whereType<Map>()
|
||||
.map((e) => Friendship.fromJson(
|
||||
e.map((k, v) => MapEntry(k.toString(), v)),
|
||||
))
|
||||
.where((f) => f.isAccepted)
|
||||
.toList();
|
||||
_friendships = parsed ?? [];
|
||||
} catch (e) {
|
||||
debugPrint('Failed to fetch friendships: $e');
|
||||
_friendships = [];
|
||||
} finally {
|
||||
_isFriendshipsLoading = false;
|
||||
_notifyAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchPendingFriendships() async {
|
||||
_isPendingFriendshipsLoading = true;
|
||||
try {
|
||||
final incoming = await _fetchPending('incoming');
|
||||
final outgoing = await _fetchPending('outgoing');
|
||||
_pendingIncoming = incoming;
|
||||
_pendingOutgoing = outgoing;
|
||||
} catch (e) {
|
||||
debugPrint('Failed to fetch pending friendships: $e');
|
||||
_pendingIncoming = [];
|
||||
_pendingOutgoing = [];
|
||||
} finally {
|
||||
_isPendingFriendshipsLoading = false;
|
||||
_notifyAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Friendship>> _fetchPending(String direction) async {
|
||||
final json = await api.get('/friendships/pending?direction=$direction');
|
||||
List<dynamic>? list;
|
||||
if (json is List) {
|
||||
list = json;
|
||||
} else if (json is Map) {
|
||||
for (final key in ['friendships', 'data', 'items', 'results']) {
|
||||
final value = json[key];
|
||||
if (value is List) {
|
||||
list = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list
|
||||
?.whereType<Map>()
|
||||
.map((e) => Friendship.fromJson(
|
||||
e.map((k, v) => MapEntry(k.toString(), v)),
|
||||
))
|
||||
.where((f) => f.isPending)
|
||||
.toList() ??
|
||||
const [];
|
||||
}
|
||||
|
||||
Future<Friendship?> fetchFriendshipById(String friendshipId) async {
|
||||
try {
|
||||
final json = await api.get('/friendships/$friendshipId');
|
||||
if (json is Map) {
|
||||
return Friendship.fromJson(
|
||||
json.map((k, v) => MapEntry(k.toString(), v)),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Failed to fetch friendship $friendshipId: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<List<UserSummary>> searchUsers(
|
||||
String query, {
|
||||
bool friendsOnly = false,
|
||||
}) async {
|
||||
final encoded = Uri.encodeComponent(query);
|
||||
final json = await api.get(
|
||||
'/users/search?search=$encoded${friendsOnly ? '&friends_only=true' : ''}',
|
||||
);
|
||||
List<dynamic>? list;
|
||||
if (json is List) {
|
||||
list = json;
|
||||
} else if (json is Map) {
|
||||
for (final key in ['users', 'data', 'results', 'items']) {
|
||||
final value = json[key];
|
||||
if (value is List) {
|
||||
list = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list == null) return const [];
|
||||
return list
|
||||
.whereType<Map>()
|
||||
.map((e) => UserSummary.fromJson(
|
||||
e.map((k, v) => MapEntry(k.toString(), v)),
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<Friendship> fetchFriendshipStatus(String targetUserId) async {
|
||||
try {
|
||||
final json = await api.get('/friendships/status/$targetUserId');
|
||||
if (json is Map) {
|
||||
return Friendship.fromStatusJson(
|
||||
json.map((k, v) => MapEntry(k.toString(), v)),
|
||||
targetUserId: targetUserId,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Failed to fetch friendship status for $targetUserId: $e');
|
||||
}
|
||||
return Friendship(
|
||||
id: null,
|
||||
status: 'none',
|
||||
requesterId: '',
|
||||
addresseeId: targetUserId,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Friendship> requestFriendship(
|
||||
String targetUserId, {
|
||||
UserSummary? targetUser,
|
||||
}) async {
|
||||
final json = await api.post('/friendships/request', {
|
||||
"target_user_id": targetUserId,
|
||||
});
|
||||
final friendship = _parseAndUpsertFriendship(
|
||||
json,
|
||||
fallbackStatus: 'pending',
|
||||
overrideAddressee: targetUser,
|
||||
);
|
||||
_pendingOutgoing = [friendship, ..._pendingOutgoing];
|
||||
_notifyAsync();
|
||||
return friendship;
|
||||
}
|
||||
|
||||
Future<Friendship> acceptFriendship(String friendshipId) async {
|
||||
final json = await api.post('/friendships/$friendshipId/accept', {});
|
||||
final friendship = _parseAndUpsertFriendship(json, fallbackStatus: 'accepted');
|
||||
_pendingIncoming = _pendingIncoming.where((f) => f.id != friendshipId).toList();
|
||||
_notifyAsync();
|
||||
return friendship;
|
||||
}
|
||||
|
||||
Future<Friendship> rejectFriendship(String friendshipId) async {
|
||||
final json = await api.post('/friendships/$friendshipId/reject', {});
|
||||
final friendship = _parseAndUpsertFriendship(json, fallbackStatus: 'declined');
|
||||
_pendingIncoming = _pendingIncoming.where((f) => f.id != friendshipId).toList();
|
||||
_notifyAsync();
|
||||
return friendship;
|
||||
}
|
||||
|
||||
Future<Friendship> cancelFriendship(String friendshipId) async {
|
||||
final json = await api.post('/friendships/$friendshipId/cancel', {});
|
||||
final friendship =
|
||||
_parseAndRemoveFriendship(json, friendshipId, status: 'none');
|
||||
_pendingOutgoing =
|
||||
_pendingOutgoing.where((f) => f.id != friendshipId).toList();
|
||||
_notifyAsync();
|
||||
return friendship;
|
||||
}
|
||||
|
||||
Future<void> deleteFriendship(String friendshipId) async {
|
||||
try {
|
||||
await api.delete('/friendships/$friendshipId');
|
||||
} catch (e) {
|
||||
debugPrint('Failed to delete friendship $friendshipId: $e');
|
||||
rethrow;
|
||||
}
|
||||
_friendships = _friendships.where((f) => f.id != friendshipId).toList();
|
||||
_pendingIncoming =
|
||||
_pendingIncoming.where((f) => f.id != friendshipId).toList();
|
||||
_pendingOutgoing =
|
||||
_pendingOutgoing.where((f) => f.id != friendshipId).toList();
|
||||
_notifyAsync();
|
||||
}
|
||||
|
||||
Future<Friendship> blockUser(String targetUserId) async {
|
||||
final json = await api.post('/friendships/block', {
|
||||
"target_user_id": targetUserId,
|
||||
});
|
||||
final friendship = _parseAndUpsertFriendship(json, fallbackStatus: 'blocked');
|
||||
_pendingIncoming = _pendingIncoming
|
||||
.where((f) => f.addresseeId != targetUserId && f.requesterId != targetUserId)
|
||||
.toList();
|
||||
_pendingOutgoing = _pendingOutgoing
|
||||
.where((f) => f.addresseeId != targetUserId && f.requesterId != targetUserId)
|
||||
.toList();
|
||||
_notifyAsync();
|
||||
return friendship;
|
||||
}
|
||||
|
||||
Friendship _parseAndUpsertFriendship(
|
||||
dynamic json, {
|
||||
String fallbackStatus = 'none',
|
||||
UserSummary? overrideAddressee,
|
||||
}) {
|
||||
Friendship friendship;
|
||||
if (json is Map) {
|
||||
friendship = Friendship.fromJson(
|
||||
json.map((k, v) => MapEntry(k.toString(), v)),
|
||||
);
|
||||
} else {
|
||||
friendship = Friendship(
|
||||
id: null,
|
||||
status: fallbackStatus,
|
||||
requesterId: '',
|
||||
addresseeId: '',
|
||||
);
|
||||
}
|
||||
if (overrideAddressee != null &&
|
||||
(friendship.addressee == null ||
|
||||
friendship.addressee!.userId.isEmpty ||
|
||||
friendship.addressee!.displayName.isEmpty)) {
|
||||
friendship = friendship.copyWith(
|
||||
addressee: overrideAddressee,
|
||||
addresseeId: overrideAddressee.userId,
|
||||
);
|
||||
}
|
||||
_upsertFriendship(friendship);
|
||||
return friendship;
|
||||
}
|
||||
|
||||
Friendship _parseAndRemoveFriendship(
|
||||
dynamic json,
|
||||
String friendshipId, {
|
||||
required String status,
|
||||
}) {
|
||||
Friendship friendship;
|
||||
if (json is Map) {
|
||||
friendship = Friendship.fromJson(
|
||||
json.map((k, v) => MapEntry(k.toString(), v)),
|
||||
);
|
||||
} else {
|
||||
friendship = Friendship(
|
||||
id: friendshipId,
|
||||
status: status,
|
||||
requesterId: '',
|
||||
addresseeId: '',
|
||||
);
|
||||
}
|
||||
_friendships = _friendships.where((f) => f.id != friendshipId).toList();
|
||||
_notifyAsync();
|
||||
return friendship;
|
||||
}
|
||||
|
||||
void _upsertFriendship(Friendship friendship) {
|
||||
if (friendship.id == null || friendship.id!.isEmpty) {
|
||||
_notifyAsync();
|
||||
return;
|
||||
}
|
||||
final idx = _friendships.indexWhere((f) => f.id == friendship.id);
|
||||
if (idx >= 0) {
|
||||
_friendships[idx] = friendship;
|
||||
} else {
|
||||
_friendships = [friendship, ..._friendships];
|
||||
}
|
||||
_friendships = _friendships.where((f) => f.isAccepted).toList();
|
||||
_notifyAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user