From 20396c7393f8382bd4b85277f0191489f66b3384 Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Wed, 15 Nov 2023 16:05:45 -0500 Subject: [PATCH] Renaming groups to circles everywhere in code and labels --- lib/controls/standard_app_drawer.dart | 4 +- lib/data/interfaces/circles_repo_intf.dart | 27 ++++ lib/data/interfaces/groups_repo.intf.dart | 27 ---- lib/data/memory/memory_circles_repo.dart | 86 +++++++++++ lib/data/memory/memory_groups_repo.dart | 86 ----------- lib/di_initialization.dart | 12 +- lib/friendica_client/friendica_client.dart | 73 ++++----- lib/models/TimelineIdentifiers.dart | 6 +- lib/models/circle_data.dart | 22 +++ lib/models/group_data.dart | 22 --- lib/models/visibility.dart | 38 +++-- lib/routes.dart | 32 ++-- ...reen.dart => circle_add_users_screen.dart} | 43 +++--- ..._screen.dart => circle_create_screen.dart} | 28 ++-- ..._screen.dart => circle_editor_screen.dart} | 86 +++++------ ...een.dart => circle_management_screen.dart} | 22 +-- lib/screens/editor.dart | 44 +++--- lib/screens/home.dart | 38 ++--- lib/screens/user_profile_screen.dart | 30 ++-- .../visibility_friendica_extensions.dart | 16 +- .../circle_data_mastodon_extensions.dart | 8 + .../group_data_mastodon_extensions.dart | 8 - .../visibility_mastodon_extensions.dart | 10 +- lib/services/connections_manager.dart | 142 +++++++++--------- lib/services/timeline_manager.dart | 34 ++--- 25 files changed, 472 insertions(+), 472 deletions(-) create mode 100644 lib/data/interfaces/circles_repo_intf.dart delete mode 100644 lib/data/interfaces/groups_repo.intf.dart create mode 100644 lib/data/memory/memory_circles_repo.dart delete mode 100644 lib/data/memory/memory_groups_repo.dart create mode 100644 lib/models/circle_data.dart delete mode 100644 lib/models/group_data.dart rename lib/screens/{group_add_users_screen.dart => circle_add_users_screen.dart} (81%) rename lib/screens/{group_create_screen.dart => circle_create_screen.dart} (65%) rename lib/screens/{group_editor_screen.dart => circle_editor_screen.dart} (77%) rename lib/screens/{group_management_screen.dart => circle_management_screen.dart} (71%) create mode 100644 lib/serializers/mastodon/circle_data_mastodon_extensions.dart delete mode 100644 lib/serializers/mastodon/group_data_mastodon_extensions.dart diff --git a/lib/controls/standard_app_drawer.dart b/lib/controls/standard_app_drawer.dart index 16277aa..8a54540 100644 --- a/lib/controls/standard_app_drawer.dart +++ b/lib/controls/standard_app_drawer.dart @@ -86,8 +86,8 @@ class StandardAppDrawer extends StatelessWidget { ), buildMenuButton( context, - 'Groups Management', - () => context.pushNamed(ScreenPaths.groupManagement), + 'Circles Management', + () => context.pushNamed(ScreenPaths.circleManagement), ), buildMenuButton( context, diff --git a/lib/data/interfaces/circles_repo_intf.dart b/lib/data/interfaces/circles_repo_intf.dart new file mode 100644 index 0000000..b64f618 --- /dev/null +++ b/lib/data/interfaces/circles_repo_intf.dart @@ -0,0 +1,27 @@ +import 'package:result_monad/result_monad.dart'; + +import '../../models/circle_data.dart'; +import '../../models/connection.dart'; +import '../../models/exec_error.dart'; + +abstract class ICirclesRepo { + void clear(); + + void addAllCircles(List circles); + + void addConnectionToCircle(CircleData circle, Connection connection); + + void clearMyCircles(); + + void upsertCircle(CircleData circle); + + void deleteCircle(CircleData circle); + + List getMyCircles(); + + Result, ExecError> getCircleMembers(CircleData circle); + + Result, ExecError> getCirclesForUser(String id); + + bool updateConnectionCircleData(String id, List currentCircless); +} diff --git a/lib/data/interfaces/groups_repo.intf.dart b/lib/data/interfaces/groups_repo.intf.dart deleted file mode 100644 index c0133e9..0000000 --- a/lib/data/interfaces/groups_repo.intf.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:result_monad/result_monad.dart'; - -import '../../models/connection.dart'; -import '../../models/exec_error.dart'; -import '../../models/group_data.dart'; - -abstract class IGroupsRepo { - void clear(); - - void addAllGroups(List groups); - - void addConnectionToGroup(GroupData group, Connection connection); - - void clearMyGroups(); - - void upsertGroup(GroupData group); - - void deleteGroup(GroupData group); - - List getMyGroups(); - - Result, ExecError> getGroupMembers(GroupData group); - - Result, ExecError> getGroupsForUser(String id); - - bool updateConnectionGroupData(String id, List currentGroups); -} diff --git a/lib/data/memory/memory_circles_repo.dart b/lib/data/memory/memory_circles_repo.dart new file mode 100644 index 0000000..a19133a --- /dev/null +++ b/lib/data/memory/memory_circles_repo.dart @@ -0,0 +1,86 @@ +import 'package:result_monad/result_monad.dart'; + +import '../../models/circle_data.dart'; +import '../../models/connection.dart'; +import '../../models/exec_error.dart'; +import '../interfaces/circles_repo_intf.dart'; + +class MemoryCirclesRepo implements ICirclesRepo { + final _circlesForConnection = >{}; + final _connectionsForCircle = >{}; + final _myCircles = {}; + + @override + void clear() { + _circlesForConnection.clear(); + _connectionsForCircle.clear(); + _myCircles.clear(); + } + + @override + Result, ExecError> getCirclesForUser(String id) { + if (!_circlesForConnection.containsKey(id)) { + return Result.error(ExecError( + type: ErrorType.notFound, + message: '$id not a known user ID', + )); + } + + return Result.ok(_circlesForConnection[id]!); + } + + @override + List getMyCircles() { + return _myCircles.toList(); + } + + @override + Result, ExecError> getCircleMembers(CircleData circle) { + if (_connectionsForCircle.containsKey(circle.id)) { + return Result.ok(_connectionsForCircle[circle.id]!.toList()); + } + + return buildErrorResult( + type: ErrorType.notFound, + message: 'Circle ${circle.id} not found', + ); + } + + @override + void clearMyCircles() { + _myCircles.clear(); + } + + @override + void addConnectionToCircle(CircleData circle, Connection connection) { + _connectionsForCircle.putIfAbsent(circle.id, () => {}).add(connection); + _circlesForConnection[connection.id]?.add(circle); + } + + @override + void addAllCircles(List circle) { + _myCircles.addAll(circle); + } + + @override + bool updateConnectionCircleData(String id, List currentCircles) { + _circlesForConnection[id] = currentCircles; + return true; + } + + @override + void upsertCircle(CircleData circle) { + _connectionsForCircle.putIfAbsent(circle.id, () => {}); + _myCircles.remove(circle); + _myCircles.add(circle); + } + + @override + void deleteCircle(CircleData circle) { + for (final conCircles in _circlesForConnection.values) { + conCircles.remove(circle); + } + _connectionsForCircle.remove(circle.id); + _myCircles.remove(circle); + } +} diff --git a/lib/data/memory/memory_groups_repo.dart b/lib/data/memory/memory_groups_repo.dart deleted file mode 100644 index 0d3317c..0000000 --- a/lib/data/memory/memory_groups_repo.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'package:result_monad/result_monad.dart'; - -import '../../models/connection.dart'; -import '../../models/exec_error.dart'; -import '../../models/group_data.dart'; -import '../interfaces/groups_repo.intf.dart'; - -class MemoryGroupsRepo implements IGroupsRepo { - final _groupsForConnection = >{}; - final _connectionsForGroup = >{}; - final _myGroups = {}; - - @override - void clear() { - _groupsForConnection.clear(); - _connectionsForGroup.clear(); - _myGroups.clear(); - } - - @override - Result, ExecError> getGroupsForUser(String id) { - if (!_groupsForConnection.containsKey(id)) { - return Result.error(ExecError( - type: ErrorType.notFound, - message: '$id not a known user ID', - )); - } - - return Result.ok(_groupsForConnection[id]!); - } - - @override - List getMyGroups() { - return _myGroups.toList(); - } - - @override - Result, ExecError> getGroupMembers(GroupData group) { - if (_connectionsForGroup.containsKey(group.id)) { - return Result.ok(_connectionsForGroup[group.id]!.toList()); - } - - return buildErrorResult( - type: ErrorType.notFound, - message: 'Group ${group.id} not found', - ); - } - - @override - void clearMyGroups() { - _myGroups.clear(); - } - - @override - void addConnectionToGroup(GroupData group, Connection connection) { - _connectionsForGroup.putIfAbsent(group.id, () => {}).add(connection); - _groupsForConnection[connection.id]?.add(group); - } - - @override - void addAllGroups(List groups) { - _myGroups.addAll(groups); - } - - @override - bool updateConnectionGroupData(String id, List currentGroups) { - _groupsForConnection[id] = currentGroups; - return true; - } - - @override - void upsertGroup(GroupData group) { - _connectionsForGroup.putIfAbsent(group.id, () => {}); - _myGroups.remove(group); - _myGroups.add(group); - } - - @override - void deleteGroup(GroupData group) { - for (final conGroups in _groupsForConnection.values) { - conGroups.remove(group); - } - _connectionsForGroup.remove(group.id); - _myGroups.remove(group); - } -} diff --git a/lib/di_initialization.dart b/lib/di_initialization.dart index b25ea8f..4e0120c 100644 --- a/lib/di_initialization.dart +++ b/lib/di_initialization.dart @@ -4,10 +4,10 @@ import 'package:logging/logging.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; +import 'data/interfaces/circles_repo_intf.dart'; import 'data/interfaces/connections_repo_intf.dart'; -import 'data/interfaces/groups_repo.intf.dart'; import 'data/interfaces/hashtag_repo_intf.dart'; -import 'data/memory/memory_groups_repo.dart'; +import 'data/memory/memory_circles_repo.dart'; import 'data/objectbox/objectbox_cache.dart'; import 'data/objectbox/objectbox_connections_repo.dart'; import 'data/objectbox/objectbox_hashtag_repo.dart'; @@ -96,8 +96,8 @@ Future dependencyInjectionInitialization() async { ActiveProfileSelector((p) => ReshareViaService()) ..subscribeToProfileSwaps()); - getIt.registerSingleton>( - ActiveProfileSelector((p) => MemoryGroupsRepo()) + getIt.registerSingleton>( + ActiveProfileSelector((p) => MemoryCirclesRepo()) ..subscribeToProfileSwaps()); getIt.registerSingleton>( @@ -105,7 +105,7 @@ Future dependencyInjectionInitialization() async { (p) => ConnectionsManager( p, getIt>().getForProfile(p).value, - getIt>().getForProfile(p).value, + getIt>().getForProfile(p).value, ), )); @@ -118,7 +118,7 @@ Future dependencyInjectionInitialization() async { getIt.registerSingleton>( ActiveProfileSelector((p) => TimelineManager( p, - getIt>().getForProfile(p).value, + getIt>().getForProfile(p).value, getIt>() .getForProfile(p) .value, diff --git a/lib/friendica_client/friendica_client.dart b/lib/friendica_client/friendica_client.dart index dec4487..3033d2c 100644 --- a/lib/friendica_client/friendica_client.dart +++ b/lib/friendica_client/friendica_client.dart @@ -10,12 +10,12 @@ import '../friendica_client/paged_response.dart'; import '../globals.dart'; import '../models/TimelineIdentifiers.dart'; import '../models/auth/profile.dart'; +import '../models/circle_data.dart'; import '../models/connection.dart'; import '../models/direct_message.dart'; import '../models/exec_error.dart'; import '../models/follow_request.dart'; import '../models/gallery_data.dart'; -import '../models/group_data.dart'; import '../models/image_entry.dart'; import '../models/instance_info.dart'; import '../models/media_attachment_uploads/image_types_enum.dart'; @@ -28,9 +28,9 @@ import '../serializers/friendica/direct_message_friendica_extensions.dart'; import '../serializers/friendica/gallery_data_friendica_extensions.dart'; import '../serializers/friendica/image_entry_friendica_extensions.dart'; import '../serializers/friendica/visibility_friendica_extensions.dart'; +import '../serializers/mastodon/circle_data_mastodon_extensions.dart'; import '../serializers/mastodon/connection_mastodon_extensions.dart'; import '../serializers/mastodon/follow_request_mastodon_extensions.dart'; -import '../serializers/mastodon/group_data_mastodon_extensions.dart'; import '../serializers/mastodon/instance_info_mastodon_extensions.dart'; import '../serializers/mastodon/notification_mastodon_extension.dart'; import '../serializers/mastodon/search_result_mastodon_extensions.dart'; @@ -168,32 +168,33 @@ class GalleryClient extends FriendicaClient { } } -class GroupsClient extends FriendicaClient { - static final _logger = Logger('$GroupsClient'); +class CirclesClient extends FriendicaClient { + static final _logger = Logger('$CirclesClient'); - GroupsClient(super.credentials) : super(); + CirclesClient(super.credentials) : super(); - FutureResult, ExecError> getGroups() async { - _logger.finest(() => 'Getting group (Mastodon List) data'); + FutureResult, ExecError> getCircles() async { + _logger.finest(() => 'Getting circle (Mastodon List) data'); final url = 'https://$serverName/api/v1/lists'; final request = Uri.parse(url); return (await _getApiListRequest(request).andThenSuccessAsync( (listsJson) async => listsJson.data - .map((json) => GroupDataMastodonExtensions.fromJson(json)) + .map((json) => CircleDataMastodonExtensions.fromJson(json)) .toList())) .mapError((error) => error is ExecError ? error : ExecError(type: ErrorType.localError, message: error.toString())); } - FutureResult>, ExecError> getGroupMembers( - GroupData groupData, + FutureResult>, ExecError> getCircleMembers( + CircleData circleData, PagingData page, ) async { _networkStatusService.startConnectionUpdateStatus(); _logger.finest(() => - 'Getting members for group (Mastodon List) of name ${groupData.name} with paging: $page'); - final baseUrl = 'https://$serverName/api/v1/lists/${groupData.id}/accounts'; + 'Getting members for circle (Mastodon List) of name ${circleData.name} with paging: $page'); + final baseUrl = + 'https://$serverName/api/v1/lists/${circleData.id}/accounts'; final url = Uri.parse('$baseUrl?${page.toQueryParameters()}'); final result = await _getApiPagedRequest(url); _networkStatusService.finishConnectionUpdateStatus(); @@ -205,8 +206,8 @@ class GroupsClient extends FriendicaClient { .execErrorCast(); } - FutureResult createGroup(String title) async { - _logger.finest(() => 'Creating group (Mastodon List) of name $title'); + FutureResult createCircle(String title) async { + _logger.finest(() => 'Creating circle (Mastodon List) of name $title'); final url = 'https://$serverName/api/v1/lists'; final body = { 'title': title, @@ -215,14 +216,14 @@ class GroupsClient extends FriendicaClient { Uri.parse(url), body, headers: _headers, - ).andThenSuccessAsync( - (data) async => GroupDataMastodonExtensions.fromJson(jsonDecode(data))); + ).andThenSuccessAsync((data) async => + CircleDataMastodonExtensions.fromJson(jsonDecode(data))); return result.execErrorCast(); } - FutureResult renameGroup( + FutureResult renameCircle( String id, String title) async { - _logger.finest(() => 'Reanming group (Mastodon List) to name $title'); + _logger.finest(() => 'Reanming circle (Mastodon List) to name $title'); final url = 'https://$serverName/api/v1/lists/$id'; final body = { 'title': title, @@ -233,38 +234,38 @@ class GroupsClient extends FriendicaClient { headers: _headers, ).andThenSuccessAsync((data) async { final json = jsonDecode(data); - return GroupDataMastodonExtensions.fromJson(json); + return CircleDataMastodonExtensions.fromJson(json); }); return result.execErrorCast(); } - FutureResult deleteGroup(GroupData groupData) async { + FutureResult deleteCircle(CircleData circleData) async { _logger.finest( - () => 'Reanming group (Mastodon List) to name ${groupData.name}'); - final url = 'https://$serverName/api/v1/lists/${groupData.id}'; + () => 'Reanming circle (Mastodon List) to name ${circleData.name}'); + final url = 'https://$serverName/api/v1/lists/${circleData.id}'; final result = await deleteUrl(Uri.parse(url), {}, headers: _headers); return result.mapValue((_) => true).execErrorCast(); } - FutureResult, ExecError> getMemberGroupsForConnection( + FutureResult, ExecError> getMemberCirclesForConnection( String connectionId) async { _logger.finest(() => - 'Getting groups (Mastodon Lists) containing connection: $connectionId'); + 'Getting circles (Mastodon Lists) containing connection: $connectionId'); final url = 'https://$serverName/api/v1/accounts/$connectionId/lists'; final request = Uri.parse(url); return (await _getApiListRequest(request).andThenSuccessAsync( (listsJson) async => listsJson.data - .map((json) => GroupDataMastodonExtensions.fromJson(json)) + .map((json) => CircleDataMastodonExtensions.fromJson(json)) .toList())) .mapError((error) => error as ExecError); } - FutureResult addConnectionToGroup( - GroupData group, + FutureResult addConnectionToCircle( + CircleData circle, Connection connection, ) async { - _logger.finest(() => 'Adding connection to group'); - final url = 'https://$serverName/api/v1/lists/${group.id}/accounts'; + _logger.finest(() => 'Adding connection to circle'); + final url = 'https://$serverName/api/v1/lists/${circle.id}/accounts'; final request = Uri.parse(url); final requestData = { 'account_ids': [connection.id] @@ -273,12 +274,12 @@ class GroupsClient extends FriendicaClient { .mapValue((_) => true); } - FutureResult removeConnectionFromGroup( - GroupData group, + FutureResult removeConnectionFromCircle( + CircleData circle, Connection connection, ) async { - _logger.finest(() => 'Adding connection to group'); - final url = 'https://$serverName/api/v1/lists/${group.id}/accounts'; + _logger.finest(() => 'Adding connection to circle'); + final url = 'https://$serverName/api/v1/lists/${circle.id}/accounts'; final request = Uri.parse(url); final requestData = { 'account_ids': [connection.id] @@ -549,7 +550,7 @@ class RelationshipsClient extends FriendicaClient { FutureResult getConnectionWithStatus( Connection connection) async { - _logger.finest(() => 'Getting group (Mastodon List) data'); + _logger.finest(() => 'Getting circle (Mastodon List) data'); _networkStatusService.startConnectionUpdateStatus(); final myId = profile.userId; final id = int.parse(connection.id); @@ -1044,7 +1045,7 @@ class TimelineClient extends FriendicaClient { return 'timelines/public'; case TimelineType.local: return 'timelines/public'; - case TimelineType.group: + case TimelineType.circle: return 'timelines/list/${type.auxData}'; case TimelineType.profile: return '/accounts/${type.auxData}/statuses'; @@ -1059,7 +1060,7 @@ class TimelineClient extends FriendicaClient { case TimelineType.home: case TimelineType.global: case TimelineType.profile: - case TimelineType.group: + case TimelineType.circle: case TimelineType.self: return ''; case TimelineType.local: diff --git a/lib/models/TimelineIdentifiers.dart b/lib/models/TimelineIdentifiers.dart index b98a385..43e81e7 100644 --- a/lib/models/TimelineIdentifiers.dart +++ b/lib/models/TimelineIdentifiers.dart @@ -2,7 +2,7 @@ enum TimelineType { home, global, local, - group, + circle, profile, self; @@ -14,8 +14,8 @@ enum TimelineType { return 'Global Fediverse'; case TimelineType.local: return 'Local Fediverse'; - case TimelineType.group: - return 'Groups (Lists)'; + case TimelineType.circle: + return 'Circles'; case TimelineType.profile: return 'Profile'; case TimelineType.self: diff --git a/lib/models/circle_data.dart b/lib/models/circle_data.dart new file mode 100644 index 0000000..81cb20c --- /dev/null +++ b/lib/models/circle_data.dart @@ -0,0 +1,22 @@ +class CircleData { + static final followersPseudoCircle = CircleData('~', 'Followers'); + + final String id; + + final String name; + + CircleData(this.id, this.name); + + @override + String toString() { + return 'CircleData{id: $id, name: $name}'; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is CircleData && runtimeType == other.runtimeType && id == other.id; + + @override + int get hashCode => id.hashCode; +} diff --git a/lib/models/group_data.dart b/lib/models/group_data.dart deleted file mode 100644 index bd2c411..0000000 --- a/lib/models/group_data.dart +++ /dev/null @@ -1,22 +0,0 @@ -class GroupData { - static final followersPseudoGroup = GroupData('~', 'Followers'); - - final String id; - - final String name; - - GroupData(this.id, this.name); - - @override - String toString() { - return 'GroupData{id: $id, name: $name}'; - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is GroupData && runtimeType == other.runtimeType && id == other.id; - - @override - int get hashCode => id.hashCode; -} diff --git a/lib/models/visibility.dart b/lib/models/visibility.dart index 4c635a1..84f7762 100644 --- a/lib/models/visibility.dart +++ b/lib/models/visibility.dart @@ -20,50 +20,48 @@ class Visibility { final List excludedUserIds; - final List allowedGroupIds; + final List allowedCircleIds; - final List excludedGroupIds; + final List excludedCircleIds; bool get hasDetails => allowedUserIds.isNotEmpty || - excludedUserIds.isNotEmpty || - allowedGroupIds.isNotEmpty || - excludedGroupIds.isNotEmpty; + excludedUserIds.isNotEmpty || + allowedCircleIds.isNotEmpty || + excludedCircleIds.isNotEmpty; const Visibility({ required this.type, this.allowedUserIds = const [], this.excludedUserIds = const [], - this.allowedGroupIds = const [], - this.excludedGroupIds = const [], + this.allowedCircleIds = const [], + this.excludedCircleIds = const [], }); - factory Visibility.public() => - const Visibility( + factory Visibility.public() => const Visibility( type: VisibilityType.public, ); - factory Visibility.private() => - const Visibility( + factory Visibility.private() => const Visibility( type: VisibilityType.private, ); @override bool operator ==(Object other) => identical(this, other) || - other is Visibility && - runtimeType == other.runtimeType && - type == other.type && - allowedUserIds == other.allowedUserIds && - excludedUserIds == other.excludedUserIds && - allowedGroupIds == other.allowedGroupIds && - excludedGroupIds == other.excludedGroupIds; + other is Visibility && + runtimeType == other.runtimeType && + type == other.type && + allowedUserIds == other.allowedUserIds && + excludedUserIds == other.excludedUserIds && + allowedCircleIds == other.allowedCircleIds && + excludedCircleIds == other.excludedCircleIds; @override int get hashCode => type.hashCode ^ allowedUserIds.hashCode ^ excludedUserIds.hashCode ^ - allowedGroupIds.hashCode ^ - excludedGroupIds.hashCode; + allowedCircleIds.hashCode ^ + excludedCircleIds.hashCode; } diff --git a/lib/routes.dart b/lib/routes.dart index a7280b3..2bbeb8a 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -3,6 +3,10 @@ import 'package:go_router/go_router.dart'; import 'globals.dart'; import 'models/interaction_type_enum.dart'; import 'screens/blocks_screen.dart'; +import 'screens/circle_add_users_screen.dart'; +import 'screens/circle_create_screen.dart'; +import 'screens/circle_editor_screen.dart'; +import 'screens/circle_management_screen.dart'; import 'screens/contacts_screen.dart'; import 'screens/editor.dart'; import 'screens/filter_editor_screen.dart'; @@ -10,10 +14,6 @@ import 'screens/filters_screen.dart'; import 'screens/follow_request_adjudication_screen.dart'; import 'screens/gallery_browsers_screen.dart'; import 'screens/gallery_screen.dart'; -import 'screens/group_add_users_screen.dart'; -import 'screens/group_create_screen.dart'; -import 'screens/group_editor_screen.dart'; -import 'screens/group_management_screen.dart'; import 'screens/home.dart'; import 'screens/image_editor_screen.dart'; import 'screens/interactions_viewer_screen.dart'; @@ -44,7 +44,7 @@ class ScreenPaths { static String notifications = '/notifications'; static String signin = '/signin'; static String manageProfiles = '/switchProfiles'; - static String groupManagement = '/group_management'; + static String circleManagement = '/circle_management'; static String signup = '/signup'; static String userProfile = '/user_profile'; static String userPosts = '/user_posts'; @@ -127,8 +127,8 @@ final appRouter = GoRouter( GoRoute( path: '/connect/:id', name: ScreenPaths.connectHandle, - builder: (context, state) => - FollowRequestAdjudicationScreen(userId: state.pathParameters['id']!), + builder: (context, state) => FollowRequestAdjudicationScreen( + userId: state.pathParameters['id']!), ), GoRoute( path: ScreenPaths.timelines, @@ -156,28 +156,28 @@ final appRouter = GoRouter( GoRoute( name: ScreenPaths.thread, path: ScreenPaths.thread, - builder: (context, state) => - MessageThreadScreen(parentThreadId: state.uri.queryParameters['uri']!), + builder: (context, state) => MessageThreadScreen( + parentThreadId: state.uri.queryParameters['uri']!), ), GoRoute( - name: ScreenPaths.groupManagement, - path: ScreenPaths.groupManagement, - builder: (context, state) => const GroupManagementScreen(), + name: ScreenPaths.circleManagement, + path: ScreenPaths.circleManagement, + builder: (context, state) => const CircleManagementScreen(), routes: [ GoRoute( path: 'show/:id', - builder: (context, state) => GroupEditorScreen( - groupId: state.pathParameters['id']!, + builder: (context, state) => CircleEditorScreen( + circleId: state.pathParameters['id']!, ), ), GoRoute( path: 'new', - builder: (context, state) => const GroupCreateScreen(), + builder: (context, state) => const CircleCreateScreen(), ), GoRoute( path: 'add_users/:id', builder: (context, state) => - GroupAddUsersScreen(groupId: state.pathParameters['id']!), + CircleAddUsersScreen(circleId: state.pathParameters['id']!), ), ], ), diff --git a/lib/screens/group_add_users_screen.dart b/lib/screens/circle_add_users_screen.dart similarity index 81% rename from lib/screens/group_add_users_screen.dart rename to lib/screens/circle_add_users_screen.dart index 9b0f9b4..0ebf071 100644 --- a/lib/screens/group_add_users_screen.dart +++ b/lib/screens/circle_add_users_screen.dart @@ -8,47 +8,47 @@ import '../controls/linear_status_indicator.dart'; import '../controls/responsive_max_width.dart'; import '../controls/status_and_refresh_button.dart'; import '../globals.dart'; +import '../models/circle_data.dart'; import '../models/connection.dart'; import '../models/exec_error.dart'; -import '../models/group_data.dart'; import '../routes.dart'; import '../services/connections_manager.dart'; import '../services/network_status_service.dart'; import '../utils/active_profile_selector.dart'; import '../utils/snackbar_builder.dart'; -class GroupAddUsersScreen extends StatefulWidget { - final String groupId; +class CircleAddUsersScreen extends StatefulWidget { + final String circleId; - const GroupAddUsersScreen({super.key, required this.groupId}); + const CircleAddUsersScreen({super.key, required this.circleId}); @override - State createState() => _GroupAddUsersScreenState(); + State createState() => _CircleAddUsersScreenState(); } -class _GroupAddUsersScreenState extends State { - static final _logger = Logger('$GroupAddUsersScreen'); +class _CircleAddUsersScreenState extends State { + static final _logger = Logger('$CircleAddUsersScreen'); var filterText = ''; - late GroupData groupData; + late CircleData circleData; @override void initState() { super.initState(); final manager = getIt>().activeEntry.value; - groupData = - manager.getMyGroups().where((g) => g.id == widget.groupId).first; + circleData = + manager.getMyCircles().where((g) => g.id == widget.circleId).first; } - Future addUserToGroup( + Future addUserToCircle( ConnectionsManager manager, Connection connection, ) async { - final messageBase = '${connection.name} from ${groupData.name}'; + final messageBase = '${connection.name} from ${circleData.name}'; final confirm = await showYesNoDialog(context, 'Add $messageBase?'); if (context.mounted && confirm == true) { final message = await manager - .addUserToGroup(groupData, connection) + .addUserToCircle(circleData, connection) .withResult((p0) => setState(() {})) .fold( onSuccess: (_) => 'Added $messageBase', @@ -66,15 +66,15 @@ class _GroupAddUsersScreenState extends State { .watch>() .activeEntry .value; - final groupMembers = manager - .getGroupMembers(groupData) + final circleMembers = manager + .getCircleMembers(circleData) .withError((e) => logError(e, _logger)) .getValueOrElse(() => []) .toSet(); final allContacts = manager.getMyContacts(); final filterTextLC = filterText.toLowerCase(); final contacts = allContacts - .where((c) => !groupMembers.contains(c)) + .where((c) => !circleMembers.contains(c)) .where((c) => filterText.isEmpty || c.name.toLowerCase().contains(filterTextLC) || @@ -83,7 +83,7 @@ class _GroupAddUsersScreenState extends State { contacts.sort((c1, c2) => c1.name.compareTo(c2.name)); _logger.finer( () => - '# in group: ${groupMembers.length} # Contacts: ${allContacts.length}, #filtered: ${contacts.length}', + '# in circle: ${circleMembers.length} # Contacts: ${allContacts.length}, #filtered: ${contacts.length}', ); late Widget body; if (contacts.isEmpty) { @@ -111,7 +111,8 @@ class _GroupAddUsersScreenState extends State { softWrap: true, ), trailing: IconButton( - onPressed: () async => await addUserToGroup(manager, contact), + onPressed: () async => + await addUserToCircle(manager, contact), icon: const Icon(Icons.add)), ); }, @@ -129,14 +130,14 @@ class _GroupAddUsersScreenState extends State { if (nss.connectionUpdateStatus.value) { return; } - manager.refreshGroupMemberships(groupData); + manager.refreshCircleMemberships(circleData); return; }, child: ResponsiveMaxWidth( child: Column( children: [ Text( - 'Group: ${groupData.name}', + 'Circle: ${circleData.name}', style: Theme.of(context).textTheme.bodyLarge, softWrap: true, ), @@ -169,7 +170,7 @@ class _GroupAddUsersScreenState extends State { child: StatusAndRefreshButton( valueListenable: nss.connectionUpdateStatus, refreshFunction: () async => - manager.refreshGroupMemberships(groupData), + manager.refreshCircleMemberships(circleData), ), ) ], diff --git a/lib/screens/group_create_screen.dart b/lib/screens/circle_create_screen.dart similarity index 65% rename from lib/screens/group_create_screen.dart rename to lib/screens/circle_create_screen.dart index 423ae60..42dbfa9 100644 --- a/lib/screens/group_create_screen.dart +++ b/lib/screens/circle_create_screen.dart @@ -8,28 +8,28 @@ import '../services/connections_manager.dart'; import '../utils/active_profile_selector.dart'; import '../utils/snackbar_builder.dart'; -class GroupCreateScreen extends StatefulWidget { - const GroupCreateScreen({super.key}); +class CircleCreateScreen extends StatefulWidget { + const CircleCreateScreen({super.key}); @override - State createState() => _GroupCreateScreenState(); + State createState() => _CircleCreateScreenState(); } -class _GroupCreateScreenState extends State { - final groupTextController = TextEditingController(); +class _CircleCreateScreenState extends State { + final circleTextController = TextEditingController(); - Future createGroup(ConnectionsManager manager) async { - if (groupTextController.text.isEmpty) { - buildSnackbar(context, "Group name can't be empty"); + Future createCircle(ConnectionsManager manager) async { + if (circleTextController.text.isEmpty) { + buildSnackbar(context, "Circle name can't be empty"); return; } - final result = await manager.createGroup(groupTextController.text); + final result = await manager.createCircle(circleTextController.text); if (context.mounted) { result.match( onSuccess: (_) => context.canPop() ? context.pop() : null, onError: (error) { - buildSnackbar(context, 'Error trying to create new group: $error'); + buildSnackbar(context, 'Error trying to create new circle: $error'); }); } } @@ -44,7 +44,7 @@ class _GroupCreateScreenState extends State { return Scaffold( appBar: StandardAppBar.build( context, - 'New group', + 'New circle', withHome: false, ), body: Padding( @@ -52,10 +52,10 @@ class _GroupCreateScreenState extends State { child: Column( children: [ TextFormField( - controller: groupTextController, + controller: circleTextController, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( - labelText: 'Group Name', + labelText: 'Circle Name', border: OutlineInputBorder( borderSide: const BorderSide(), borderRadius: BorderRadius.circular(5.0), @@ -64,7 +64,7 @@ class _GroupCreateScreenState extends State { ), const VerticalPadding(), ElevatedButton( - onPressed: () => createGroup(manager), + onPressed: () => createCircle(manager), child: const Text('Create'), ), ], diff --git a/lib/screens/group_editor_screen.dart b/lib/screens/circle_editor_screen.dart similarity index 77% rename from lib/screens/group_editor_screen.dart rename to lib/screens/circle_editor_screen.dart index 9ada179..bae8c51 100644 --- a/lib/screens/group_editor_screen.dart +++ b/lib/screens/circle_editor_screen.dart @@ -9,75 +9,75 @@ import '../controls/responsive_max_width.dart'; import '../controls/standard_appbar.dart'; import '../controls/status_and_refresh_button.dart'; import '../globals.dart'; +import '../models/circle_data.dart'; import '../models/connection.dart'; -import '../models/group_data.dart'; import '../routes.dart'; import '../services/connections_manager.dart'; import '../services/network_status_service.dart'; import '../utils/active_profile_selector.dart'; import '../utils/snackbar_builder.dart'; -class GroupEditorScreen extends StatefulWidget { - final String groupId; +class CircleEditorScreen extends StatefulWidget { + final String circleId; - const GroupEditorScreen({super.key, required this.groupId}); + const CircleEditorScreen({super.key, required this.circleId}); @override - State createState() => _GroupEditorScreenState(); + State createState() => _CircleEditorScreenState(); } -class _GroupEditorScreenState extends State { - final groupTextController = TextEditingController(); +class _CircleEditorScreenState extends State { + final circleTextController = TextEditingController(); var processingUpdate = false; var allowNameEditing = false; var filterText = ''; - late GroupData groupData; + late CircleData circleData; - Future updateGroupName( + Future updateCircleName( BuildContext context, ConnectionsManager manager) async { processingUpdate = true; - final updated = groupTextController.text; - if (groupTextController.text != groupData.name) { - final confirm = await showYesNoDialog( - context, 'Change the group name from ${groupData.name} to $updated?'); + final updated = circleTextController.text; + if (circleTextController.text != circleData.name) { + final confirm = await showYesNoDialog(context, + 'Change the circle name from ${circleData.name} to $updated?'); if (context.mounted && confirm == true) { - await manager.renameGroup(widget.groupId, updated).match( - onSuccess: (updatedGroupData) { - groupData = updatedGroupData; + await manager.renameCircle(widget.circleId, updated).match( + onSuccess: (updatedCircleData) { + circleData = updatedCircleData; setState(() { allowNameEditing = false; }); }, onError: (error) { - buildSnackbar(context, 'Error renaming group: $error'); + buildSnackbar(context, 'Error renaming circle: $error'); }); } else { - groupTextController.text = groupData.name; + circleTextController.text = circleData.name; } } processingUpdate = false; } - Future deleteGroup(ConnectionsManager manager) async { + Future deleteCircle(ConnectionsManager manager) async { final confirm = await showYesNoDialog(context, - "Permanently delete group ${groupData.name}? This can't be undone."); + "Permanently delete circle ${circleData.name}? This can't be undone."); if (context.mounted && confirm == true) { - await manager.deleteGroup(groupData).match( + await manager.deleteCircle(circleData).match( onSuccess: (_) => context.canPop() ? context.pop() : null, onError: (error) => - buildSnackbar(context, 'Error trying to delete group: $error'), + buildSnackbar(context, 'Error trying to delete circle: $error'), ); } } - Future removeUserFromGroup( + Future removeUserFromCircle( ConnectionsManager manager, Connection connection, ) async { - final messageBase = '${connection.name} from ${groupData.name}'; + final messageBase = '${connection.name} from ${circleData.name}'; final confirm = await showYesNoDialog(context, 'Remove $messageBase?'); if (context.mounted && confirm == true) { final message = - await manager.removeUserFromGroup(groupData, connection).fold( + await manager.removeUserFromCircle(circleData, connection).fold( onSuccess: (_) => 'Removed $messageBase', onError: (error) => 'Error removing $messageBase: $error', ); @@ -90,14 +90,14 @@ class _GroupEditorScreenState extends State { super.initState(); final manager = getIt>().activeEntry.value; - groupData = manager - .getMyGroups() + circleData = manager + .getMyCircles() .where( - (g) => g.id == widget.groupId, + (g) => g.id == widget.circleId, ) .first; - manager.refreshGroupMemberships(groupData); - groupTextController.text = groupData.name; + manager.refreshCircleMemberships(circleData); + circleTextController.text = circleData.name; } @override @@ -110,7 +110,7 @@ class _GroupEditorScreenState extends State { final filterTextLC = filterText.toLowerCase(); final members = manager - .getGroupMembers(groupData) + .getCircleMembers(circleData) .transform((ms) => ms .where((m) => filterText.isEmpty || @@ -122,11 +122,11 @@ class _GroupEditorScreenState extends State { return Scaffold( appBar: StandardAppBar.build( context, - 'Group Editor', + 'Circle Editor', withHome: false, actions: [ IconButton( - onPressed: () => deleteGroup(manager), + onPressed: () => deleteCircle(manager), icon: const Icon(Icons.delete), ), ], @@ -135,7 +135,7 @@ class _GroupEditorScreenState extends State { padding: const EdgeInsets.all(8.0), child: RefreshIndicator( onRefresh: () async { - manager.refreshGroups(); + manager.refreshCircles(); }, child: ResponsiveMaxWidth( child: Column( @@ -153,18 +153,18 @@ class _GroupEditorScreenState extends State { if (processingUpdate) { return; } - updateGroupName(context, manager); + updateCircleName(context, manager); }, onTapOutside: (_) async { if (processingUpdate) { return; } - updateGroupName(context, manager); + updateCircleName(context, manager); }, - controller: groupTextController, + controller: circleTextController, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( - labelText: 'Group Name', + labelText: 'Circle Name', border: OutlineInputBorder( borderSide: const BorderSide(), borderRadius: BorderRadius.circular(5.0), @@ -176,7 +176,7 @@ class _GroupEditorScreenState extends State { IconButton( onPressed: () { if (allowNameEditing) { - groupTextController.text = groupData.name; + circleTextController.text = circleData.name; } setState(() { allowNameEditing = !allowNameEditing; @@ -191,12 +191,12 @@ class _GroupEditorScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('Group Members:', + Text('Circle Members:', style: Theme.of(context).textTheme.headlineSmall), IconButton( onPressed: () { context.push( - '${ScreenPaths.groupManagement}/add_users/${widget.groupId}'); + '${ScreenPaths.circleManagement}/add_users/${widget.circleId}'); }, icon: const Icon(Icons.add)), ], @@ -230,7 +230,7 @@ class _GroupEditorScreenState extends State { child: StatusAndRefreshButton( valueListenable: nss.connectionUpdateStatus, refreshFunction: () async => - manager.refreshGroupMemberships(groupData), + manager.refreshCircleMemberships(circleData), ), ) ], @@ -255,7 +255,7 @@ class _GroupEditorScreenState extends State { ), trailing: IconButton( onPressed: () async => - removeUserFromGroup(manager, m), + removeUserFromCircle(manager, m), icon: const Icon(Icons.remove), ), ); diff --git a/lib/screens/group_management_screen.dart b/lib/screens/circle_management_screen.dart similarity index 71% rename from lib/screens/group_management_screen.dart rename to lib/screens/circle_management_screen.dart index ab6fe4b..7badb83 100644 --- a/lib/screens/group_management_screen.dart +++ b/lib/screens/circle_management_screen.dart @@ -8,8 +8,8 @@ import '../routes.dart'; import '../services/connections_manager.dart'; import '../utils/active_profile_selector.dart'; -class GroupManagementScreen extends StatelessWidget { - const GroupManagementScreen({super.key}); +class CircleManagementScreen extends StatelessWidget { + const CircleManagementScreen({super.key}); @override Widget build(BuildContext context) { @@ -17,17 +17,17 @@ class GroupManagementScreen extends StatelessWidget { .watch>() .activeEntry .value; - final groups = manager.getMyGroups(); - groups.sort((g1, g2) => g1.name.compareTo(g2.name)); + final circles = manager.getMyCircles(); + circles.sort((g1, g2) => g1.name.compareTo(g2.name)); return Scaffold( appBar: StandardAppBar.build( context, - 'Groups Management', + 'Circles Management', withHome: false, actions: [ IconButton( onPressed: () => context.push( - '${ScreenPaths.groupManagement}/new', + '${ScreenPaths.circleManagement}/new', ), icon: const Icon(Icons.add), ), @@ -36,21 +36,21 @@ class GroupManagementScreen extends StatelessWidget { body: Center( child: RefreshIndicator( onRefresh: () async { - manager.refreshGroups(); + manager.refreshCircles(); }, child: ResponsiveMaxWidth( child: ListView.separated( physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { - final group = groups[index]; + final circle = circles[index]; return ListTile( - title: Text(group.name), + title: Text(circle.name), onTap: () => context.push( - '${ScreenPaths.groupManagement}/show/${group.id}'), + '${ScreenPaths.circleManagement}/show/${circle.id}'), ); }, separatorBuilder: (_, __) => const Divider(), - itemCount: groups.length, + itemCount: circles.length, ), ), ), diff --git a/lib/screens/editor.dart b/lib/screens/editor.dart index 347b8e9..5f77578 100644 --- a/lib/screens/editor.dart +++ b/lib/screens/editor.dart @@ -16,8 +16,8 @@ import '../controls/padding.dart'; import '../controls/standard_appbar.dart'; import '../controls/timeline/status_header_control.dart'; import '../globals.dart'; +import '../models/circle_data.dart'; import '../models/exec_error.dart'; -import '../models/group_data.dart'; import '../models/image_entry.dart'; import '../models/link_preview_data.dart'; import '../models/media_attachment_uploads/new_entry_media_items.dart'; @@ -56,7 +56,7 @@ class _EditorScreenState extends State { final existingMediaItems = []; final focusNode = FocusNode(); Visibility visibility = Visibility.public(); - GroupData? currentGroup; + CircleData? currentCircle; var isSubmitting = false; @@ -568,25 +568,25 @@ class _EditorScreenState extends State { ], ); } - final groups = context + final circles = context .watch>() .activeEntry - .andThen((tm) => tm.getGroups()) + .andThen((tm) => tm.getCircles()) .getValueOrElse(() => []); - groups.sort((g1, g2) => g1.name.compareTo(g2.name)); + circles.sort((g1, g2) => g1.name.compareTo(g2.name)); - final groupMenuItems = >[]; - groupMenuItems.add(DropdownMenuEntry( - value: GroupData.followersPseudoGroup, - label: GroupData.followersPseudoGroup.name)); - groupMenuItems.add(DropdownMenuEntry( - value: GroupData('', ''), label: '-', enabled: false)); - groupMenuItems.addAll(groups.map((g) => DropdownMenuEntry( + final circleMenuItems = >[]; + circleMenuItems.add(DropdownMenuEntry( + value: CircleData.followersPseudoCircle, + label: CircleData.followersPseudoCircle.name)); + circleMenuItems.add(DropdownMenuEntry( + value: CircleData('', ''), label: '-', enabled: false)); + circleMenuItems.addAll(circles.map((g) => DropdownMenuEntry( value: g, label: g.name, ))); - if (!groups.contains(currentGroup)) { - currentGroup = null; + if (!circles.contains(currentCircle)) { + currentCircle = null; } return Row( children: [ @@ -602,14 +602,14 @@ class _EditorScreenState extends State { return; } - if (value == VisibilityType.private && currentGroup == null) { + if (value == VisibilityType.private && currentCircle == null) { visibility = Visibility.private(); return; } visibility = Visibility( type: VisibilityType.private, - allowedGroupIds: [currentGroup!.id], + allowedCircleIds: [currentCircle!.id], ); }); }, @@ -622,20 +622,20 @@ class _EditorScreenState extends State { ), const HorizontalPadding(), if (visibility.type == VisibilityType.private) - DropdownMenu( + DropdownMenu( enabled: !widget.forEditing, - initialSelection: currentGroup, + initialSelection: currentCircle, onSelected: (value) { setState(() { - currentGroup = value; + currentCircle = value; visibility = Visibility( type: VisibilityType.private, - allowedGroupIds: - currentGroup == null ? [] : [currentGroup!.id], + allowedCircleIds: + currentCircle == null ? [] : [currentCircle!.id], ); }); }, - dropdownMenuEntries: groupMenuItems, + dropdownMenuEntries: circleMenuItems, ), ], ); diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 19f70dc..d92c940 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -12,7 +12,7 @@ import '../controls/standard_app_drawer.dart'; import '../controls/timeline/timeline_panel.dart'; import '../globals.dart'; import '../models/TimelineIdentifiers.dart'; -import '../models/group_data.dart'; +import '../models/circle_data.dart'; import '../services/auth_service.dart'; import '../services/network_status_service.dart'; import '../services/timeline_manager.dart'; @@ -30,18 +30,18 @@ class _HomeScreenState extends State { final postText = TextEditingController(); var currentType = TimelineType.home; - GroupData? currentGroup; + CircleData? currentCircle; final types = [ TimelineType.self, TimelineType.home, - TimelineType.global, + TimelineType.circle, TimelineType.local, - TimelineType.group, + TimelineType.circle, ]; void updateTimeline(TimelineManager manager) { - if (currentType == TimelineType.group && currentGroup == null) { - _logger.finest('Group timeline but no group selected so not updating'); + if (currentType == TimelineType.circle && currentCircle == null) { + _logger.finest('Circle timeline but no circle selected so not updating'); return; } _logger.finest('Updating timeline: $currentTimeline'); @@ -53,7 +53,7 @@ class _HomeScreenState extends State { TimelineIdentifiers get currentTimeline => TimelineIdentifiers( timeline: currentType, - auxData: currentGroup?.id ?? '', + auxData: currentCircle?.id ?? '', ); @override @@ -73,10 +73,10 @@ class _HomeScreenState extends State { .watch>() .activeEntry .value; - final groups = manager.getGroups().getValueOrElse(() => []).toList(); - groups.sort((g1, g2) => g1.name.compareTo(g2.name)); - if (!groups.contains(currentGroup)) { - currentGroup = null; + final circles = manager.getCircles().getValueOrElse(() => []).toList(); + circles.sort((g1, g2) => g1.name.compareTo(g2.name)); + if (!circles.contains(currentCircle)) { + currentCircle = null; } final timeline = TimelinePanel(timeline: currentTimeline); @@ -97,7 +97,7 @@ class _HomeScreenState extends State { title: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - if (currentType == TimelineType.group) + if (currentType == TimelineType.circle) PopupMenuButton( initialValue: currentType, // Callback that sets the selected popup menu item. @@ -113,7 +113,7 @@ class _HomeScreenState extends State { child: Text(e.toLabel()), )) .toList()), - if (currentType != TimelineType.group) + if (currentType != TimelineType.circle) DropdownButton( value: currentType, items: types @@ -131,18 +131,18 @@ class _HomeScreenState extends State { const HorizontalPadding( width: 5.0, ), - if (currentType == TimelineType.group) - DropdownButton( - value: currentGroup, - items: groups - .map((g) => DropdownMenuItem( + if (currentType == TimelineType.circle) + DropdownButton( + value: currentCircle, + items: circles + .map((g) => DropdownMenuItem( value: g, child: Text(g.name), )) .toList(), onChanged: (value) { setState(() { - currentGroup = value; + currentCircle = value; }); updateTimeline(manager); }), diff --git a/lib/screens/user_profile_screen.dart b/lib/screens/user_profile_screen.dart index ab28a8a..2253201 100644 --- a/lib/screens/user_profile_screen.dart +++ b/lib/screens/user_profile_screen.dart @@ -6,8 +6,8 @@ import '../controls/html_text_viewer_control.dart'; import '../controls/login_aware_cached_network_image.dart'; import '../controls/padding.dart'; import '../globals.dart'; +import '../models/circle_data.dart'; import '../models/connection.dart'; -import '../models/group_data.dart'; import '../routes.dart'; import '../services/auth_service.dart'; import '../services/blocks_manager.dart'; @@ -117,7 +117,7 @@ class _UserProfileScreenState extends State { const VerticalPadding(), if (profile.status == ConnectionStatus.mutual || profile.status == ConnectionStatus.youFollowThem) - buildGroups(context, profile, connectionManager), + buildCircles(context, profile, connectionManager), ], ), ), @@ -138,23 +138,23 @@ class _UserProfileScreenState extends State { ); } - Widget buildGroups( + Widget buildCircles( BuildContext context, Connection profile, ConnectionsManager manager, ) { - final myGroups = manager.getMyGroups(); - final usersGroups = manager.getGroupsForUser(profile.id).fold( - onSuccess: (groups) => groups.toSet(), + final myCircles = manager.getMyCircles(); + final usersCircles = manager.getCirclesForUser(profile.id).fold( + onSuccess: (circles) => circles.toSet(), onError: (error) { - buildSnackbar(context, 'Error getting group data: $error'); - return {}; + buildSnackbar(context, 'Error getting circle data: $error'); + return {}; }); - myGroups.sort((g1, g2) => g1.name.compareTo(g2.name)); - final groupsWidgets = myGroups.map((g) { + myCircles.sort((g1, g2) => g1.name.compareTo(g2.name)); + final circlesWidgets = myCircles.map((g) { return CheckboxListTile( title: Text(g.name), - value: usersGroups.contains(g), + value: usersCircles.contains(g), onChanged: (bool? value) async { if (isUpdating) { return; @@ -173,9 +173,9 @@ class _UserProfileScreenState extends State { isUpdating = true; }); if (isAdding) { - await manager.addUserToGroup(g, profile); + await manager.addUserToCircle(g, profile); } else { - await manager.removeUserFromGroup(g, profile); + await manager.removeUserFromCircle(g, profile); } setState(() { isUpdating = false; @@ -186,11 +186,11 @@ class _UserProfileScreenState extends State { return Column( children: [ Text( - 'Groups: ', + 'Circles: ', style: Theme.of(context).textTheme.titleMedium, ), const VerticalPadding(), - ...groupsWidgets, + ...circlesWidgets, ], ); } diff --git a/lib/serializers/friendica/visibility_friendica_extensions.dart b/lib/serializers/friendica/visibility_friendica_extensions.dart index 2a8cb7f..eff7e63 100644 --- a/lib/serializers/friendica/visibility_friendica_extensions.dart +++ b/lib/serializers/friendica/visibility_friendica_extensions.dart @@ -3,16 +3,16 @@ import '../../models/visibility.dart'; extension VisibilityFriendicaExtensions on Visibility { static Visibility fromJson(Map json) { final allowedUserIds = _parseAcl(json['allow_cid']); - final excludedGroupIds = _parseAcl(json['deny_cid']); - final allowedGroupIds = _parseAcl(json['allow_gid']); + final excludedCircleIds = _parseAcl(json['deny_cid']); + final allowedCircleIds = _parseAcl(json['allow_gid']); final excludedUserIds = _parseAcl(json['deny_cid']); final topLevelPrivate = json['friendica_private']; late final VisibilityType type; if (topLevelPrivate == null) { type = allowedUserIds.isEmpty && excludedUserIds.isEmpty && - allowedGroupIds.isEmpty && - excludedGroupIds.isEmpty + allowedCircleIds.isEmpty && + excludedCircleIds.isEmpty ? VisibilityType.public : VisibilityType.private; } else { @@ -23,8 +23,8 @@ extension VisibilityFriendicaExtensions on Visibility { type: type, allowedUserIds: allowedUserIds, excludedUserIds: excludedUserIds, - allowedGroupIds: allowedGroupIds, - excludedGroupIds: excludedGroupIds, + allowedCircleIds: allowedCircleIds, + excludedCircleIds: excludedCircleIds, ); } @@ -32,8 +32,8 @@ extension VisibilityFriendicaExtensions on Visibility { return { 'allow_cid': _idsListToAclString(allowedUserIds), 'deny_cid': _idsListToAclString(excludedUserIds), - 'allow_gid': _idsListToAclString(allowedGroupIds), - 'deny_gid': _idsListToAclString(excludedGroupIds), + 'allow_gid': _idsListToAclString(allowedCircleIds), + 'deny_gid': _idsListToAclString(excludedCircleIds), }; } diff --git a/lib/serializers/mastodon/circle_data_mastodon_extensions.dart b/lib/serializers/mastodon/circle_data_mastodon_extensions.dart new file mode 100644 index 0000000..1429d12 --- /dev/null +++ b/lib/serializers/mastodon/circle_data_mastodon_extensions.dart @@ -0,0 +1,8 @@ +import '../../models/circle_data.dart'; + +extension CircleDataMastodonExtensions on CircleData { + static CircleData fromJson(Map json) => CircleData( + json['id'], + json['title'], + ); +} diff --git a/lib/serializers/mastodon/group_data_mastodon_extensions.dart b/lib/serializers/mastodon/group_data_mastodon_extensions.dart deleted file mode 100644 index 107663f..0000000 --- a/lib/serializers/mastodon/group_data_mastodon_extensions.dart +++ /dev/null @@ -1,8 +0,0 @@ -import '../../models/group_data.dart'; - -extension GroupDataMastodonExtensions on GroupData { - static GroupData fromJson(Map json) => GroupData( - json['id'], - json['title'], - ); -} diff --git a/lib/serializers/mastodon/visibility_mastodon_extensions.dart b/lib/serializers/mastodon/visibility_mastodon_extensions.dart index 0a0d101..afbd845 100644 --- a/lib/serializers/mastodon/visibility_mastodon_extensions.dart +++ b/lib/serializers/mastodon/visibility_mastodon_extensions.dart @@ -1,4 +1,4 @@ -import 'package:relatica/models/group_data.dart'; +import 'package:relatica/models/circle_data.dart'; import '../../models/visibility.dart'; @@ -9,14 +9,14 @@ extension VisibilityMastodonExtensions on Visibility { } if (hasDetails) { - final groupId = allowedGroupIds.first; - if (groupId == GroupData.followersPseudoGroup.id) { + final circleId = allowedCircleIds.first; + if (circleId == CircleData.followersPseudoCircle.id) { return 'private'; } - return groupId; + return circleId; } return 'private'; } -} \ No newline at end of file +} diff --git a/lib/services/connections_manager.dart b/lib/services/connections_manager.dart index a49b638..67e2e93 100644 --- a/lib/services/connections_manager.dart +++ b/lib/services/connections_manager.dart @@ -5,24 +5,24 @@ import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:result_monad/result_monad.dart'; +import '../data/interfaces/circles_repo_intf.dart'; import '../data/interfaces/connections_repo_intf.dart'; -import '../data/interfaces/groups_repo.intf.dart'; import '../friendica_client/friendica_client.dart'; import '../friendica_client/paging_data.dart'; import '../globals.dart'; import '../models/auth/profile.dart'; +import '../models/circle_data.dart'; import '../models/connection.dart'; import '../models/exec_error.dart'; -import '../models/group_data.dart'; import '../utils/active_profile_selector.dart'; import 'persistent_info_service.dart'; class ConnectionsManager extends ChangeNotifier { static final _logger = Logger('$ConnectionsManager'); late final IConnectionsRepo conRepo; - late final IGroupsRepo groupsRepo; + late final ICirclesRepo circlesRepo; late final Profile profile; - var groupsNotInitialized = true; + var circlesNotInitialized = true; var _lastUpdateStatus = ''; String get lastUpdateStatus => _lastUpdateStatus.isNotEmpty @@ -34,12 +34,12 @@ class ConnectionsManager extends ChangeNotifier { .withResult((text) => _lastUpdateStatus = text) .getValueOrElse(() => 'Unknown'); - ConnectionsManager(this.profile, this.conRepo, this.groupsRepo); + ConnectionsManager(this.profile, this.conRepo, this.circlesRepo); void clear() { conRepo.clear(); - groupsRepo.clear(); - groupsNotInitialized = true; + circlesRepo.clear(); + circlesNotInitialized = true; _lastUpdateStatus = ''; notifyListeners(); } @@ -234,18 +234,18 @@ class ConnectionsManager extends ChangeNotifier { notifyListeners(); } - List getMyGroups() { - if (groupsNotInitialized) { - groupsNotInitialized = false; - _updateMyGroups(true); + List getMyCircles() { + if (circlesNotInitialized) { + circlesNotInitialized = false; + _updateMyCircles(true); } - return groupsRepo.getMyGroups(); + return circlesRepo.getMyCircles(); } - Result, ExecError> getGroupMembers(GroupData group) { - return groupsRepo - .getGroupMembers(group) + Result, ExecError> getCircleMembers(CircleData circle) { + return circlesRepo + .getCircleMembers(circle) .transform( (members) => members ..sort((c1, c2) => @@ -254,71 +254,71 @@ class ConnectionsManager extends ChangeNotifier { .execErrorCast(); } - FutureResult createGroup(String newName) async { - final result = await GroupsClient(profile) - .createGroup(newName) - .withResultAsync((newGroup) async { - groupsRepo.upsertGroup(newGroup); + FutureResult createCircle(String newName) async { + final result = await CirclesClient(profile) + .createCircle(newName) + .withResultAsync((newCircle) async { + circlesRepo.upsertCircle(newCircle); notifyListeners(); }); return result.execErrorCast(); } - FutureResult renameGroup( + FutureResult renameCircle( String id, String newName) async { - final result = await GroupsClient(profile) - .renameGroup(id, newName) - .withResultAsync((renamedGroup) async { - groupsRepo.upsertGroup(renamedGroup); + final result = await CirclesClient(profile) + .renameCircle(id, newName) + .withResultAsync((renamedCircle) async { + circlesRepo.upsertCircle(renamedCircle); notifyListeners(); }); return result.execErrorCast(); } - FutureResult deleteGroup(GroupData groupData) async { - final result = await GroupsClient(profile) - .deleteGroup(groupData) + FutureResult deleteCircle(CircleData circleData) async { + final result = await CirclesClient(profile) + .deleteCircle(circleData) .withResultAsync((_) async { - groupsRepo.deleteGroup(groupData); + circlesRepo.deleteCircle(circleData); notifyListeners(); }); return result.execErrorCast(); } - void refreshGroups() { - _updateMyGroups(true); + void refreshCircles() { + _updateMyCircles(true); } - Future refreshGroupMemberships(GroupData group) async { + Future refreshCircleMemberships(CircleData circle) async { var page = PagingData(limit: 50); - final client = GroupsClient(profile); + final client = CirclesClient(profile); final allResults = {}; var moreResults = true; while (moreResults) { - await client.getGroupMembers(group, page).match(onSuccess: (results) { + await client.getCircleMembers(circle, page).match(onSuccess: (results) { moreResults = results.data.isNotEmpty && results.next != null; page = results.next ?? page; allResults.addAll(results.data); }, onError: (error) { - _logger.severe('Error getting group listing data: $error'); + _logger.severe('Error getting circle listing data: $error'); moreResults = false; }); } - groupsRepo.deleteGroup(group); - groupsRepo.upsertGroup(group); + circlesRepo.deleteCircle(circle); + circlesRepo.upsertCircle(circle); for (final c in allResults) { upsertConnection(c); - groupsRepo.addConnectionToGroup(group, c); + circlesRepo.addConnectionToCircle(circle, c); } notifyListeners(); } - Result, ExecError> getGroupsForUser(String id) { - final result = groupsRepo.getGroupsForUser(id); + Result, ExecError> getCirclesForUser(String id) { + final result = circlesRepo.getCirclesForUser(id); if (result.isSuccess) { - print("Groups for user $id: $result"); + print("Circles for user $id: $result"); return result; } @@ -326,35 +326,35 @@ class ConnectionsManager extends ChangeNotifier { return result; } - _refreshGroupListData(id, true); + _refreshCircleListData(id, true); return Result.ok(UnmodifiableListView([])); } - FutureResult addUserToGroup( - GroupData group, Connection connection) async { - _logger.finest('Adding ${connection.name} to group: ${group.name}'); - return await GroupsClient(profile) - .addConnectionToGroup(group, connection) - .withResultAsync((_) async => await refreshGroupMemberships(group)) + FutureResult addUserToCircle( + CircleData circle, Connection connection) async { + _logger.finest('Adding ${connection.name} to circle: ${circle.name}'); + return await CirclesClient(profile) + .addConnectionToCircle(circle, connection) + .withResultAsync((_) async => await refreshCircleMemberships(circle)) .withResult((_) => notifyListeners()) .mapError((error) { - _logger - .severe('Error adding ${connection.name} from group: ${group.name}'); + _logger.severe( + 'Error adding ${connection.name} from circle: ${circle.name}'); return error; }); } - FutureResult removeUserFromGroup( - GroupData group, Connection connection) async { - _logger.finest('Removing ${connection.name} from group: ${group.name}'); - return GroupsClient(profile) - .removeConnectionFromGroup(group, connection) - .withResultAsync((_) async => await refreshGroupMemberships(group)) + FutureResult removeUserFromCircle( + CircleData circle, Connection connection) async { + _logger.finest('Removing ${connection.name} from circle: ${circle.name}'); + return CirclesClient(profile) + .removeConnectionFromCircle(circle, connection) + .withResultAsync((_) async => await refreshCircleMemberships(circle)) .withResult((_) => notifyListeners()) .mapError( (error) { _logger.severe( - 'Error removing ${connection.name} from group: ${group.name}'); + 'Error removing ${connection.name} from circle: ${circle.name}'); return error; }, ); @@ -391,19 +391,19 @@ class ConnectionsManager extends ChangeNotifier { Connection connection, { bool withNotifications = true, }) async { - await _updateMyGroups(false); - await _refreshGroupListData(connection.id, false); + await _updateMyCircles(false); + await _refreshCircleListData(connection.id, false); await _refreshConnection(connection, false); if (withNotifications) { notifyListeners(); } } - Future _refreshGroupListData(String id, bool withNotification) async { + Future _refreshCircleListData(String id, bool withNotification) async { _logger.finest('Refreshing member list data for Connection $id'); - await GroupsClient(profile).getMemberGroupsForConnection(id).match( - onSuccess: (groups) { - groupsRepo.updateConnectionGroupData(id, groups); + await CirclesClient(profile).getMemberCirclesForConnection(id).match( + onSuccess: (circles) { + circlesRepo.updateConnectionCircleData(id, circles); if (withNotification) { notifyListeners(); } @@ -432,19 +432,19 @@ class ConnectionsManager extends ChangeNotifier { ); } - Future _updateMyGroups(bool withNotification) async { - _logger.finest('Refreshing my groups list'); - await GroupsClient(profile).getGroups().match( - onSuccess: (groups) { - _logger.finest('Got updated groups:${groups.map((e) => e.name)}'); - groupsRepo.clearMyGroups(); - groupsRepo.addAllGroups(groups); + Future _updateMyCircles(bool withNotification) async { + _logger.finest('Refreshing my circles list'); + await CirclesClient(profile).getCircles().match( + onSuccess: (circles) { + _logger.finest('Got updated circles:${circles.map((e) => e.name)}'); + circlesRepo.clearMyCircles(); + circlesRepo.addAllCircles(circles); if (withNotification) { notifyListeners(); } }, onError: (error) { - _logger.severe('Error getting my groups: $error'); + _logger.severe('Error getting my circles: $error'); }, ); } diff --git a/lib/services/timeline_manager.dart b/lib/services/timeline_manager.dart index 485dd2a..07b2e6e 100644 --- a/lib/services/timeline_manager.dart +++ b/lib/services/timeline_manager.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart' hide Visibility; import 'package:logging/logging.dart'; import 'package:result_monad/result_monad.dart'; -import '../data/interfaces/groups_repo.intf.dart'; +import '../data/interfaces/circles_repo_intf.dart'; import '../friendica_client/friendica_client.dart'; import '../models/TimelineIdentifiers.dart'; import '../models/auth/profile.dart'; +import '../models/circle_data.dart'; import '../models/entry_tree_item.dart'; import '../models/exec_error.dart'; -import '../models/group_data.dart'; import '../models/image_entry.dart'; import '../models/media_attachment_uploads/new_entry_media_items.dart'; import '../models/timeline.dart'; @@ -25,38 +25,38 @@ enum TimelineRefreshType { class TimelineManager extends ChangeNotifier { static final _logger = Logger('$TimelineManager'); - final IGroupsRepo groupsRepo; + final ICirclesRepo circlesRepo; final EntryManagerService entryManagerService; - var groupsNotInitialized = true; + var circlesNotInitialized = true; final Profile profile; final cachedTimelines = {}; - TimelineManager(this.profile, this.groupsRepo, this.entryManagerService); + TimelineManager(this.profile, this.circlesRepo, this.entryManagerService); void clear() { - groupsNotInitialized = true; + circlesNotInitialized = true; cachedTimelines.clear(); entryManagerService.clear(); - groupsRepo.clear(); + circlesRepo.clear(); notifyListeners(); } - Result, ExecError> getGroups() { - if (groupsNotInitialized) { - _refreshGroupData(); - groupsNotInitialized = false; + Result, ExecError> getCircles() { + if (circlesNotInitialized) { + _refreshCircleData(); + circlesNotInitialized = false; return Result.ok([]); } - return Result.ok(groupsRepo.getMyGroups()); + return Result.ok(circlesRepo.getMyCircles()); } - Future _refreshGroupData() async { - _logger.finest('Refreshing member group data '); - await GroupsClient(profile).getGroups().match( - onSuccess: (groups) { - groupsRepo.addAllGroups(groups); + Future _refreshCircleData() async { + _logger.finest('Refreshing member circle data '); + await CirclesClient(profile).getCircles().match( + onSuccess: (circles) { + circlesRepo.addAllCircles(circles); notifyListeners(); }, onError: (error) {