mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-18 18:13:31 +00:00
Add group management screen with group creation, renaming, and deleting
This commit is contained in:
parent
9e93faad2e
commit
db7945ea77
12 changed files with 443 additions and 29 deletions
|
@ -73,6 +73,12 @@ class StandardAppDrawer extends StatelessWidget {
|
||||||
'Direct Messages',
|
'Direct Messages',
|
||||||
() => context.pushNamed(ScreenPaths.messages),
|
() => context.pushNamed(ScreenPaths.messages),
|
||||||
),
|
),
|
||||||
|
const Divider(),
|
||||||
|
buildMenuButton(
|
||||||
|
context,
|
||||||
|
'Groups Management',
|
||||||
|
() => context.pushNamed(ScreenPaths.groupManagement),
|
||||||
|
),
|
||||||
buildMenuButton(
|
buildMenuButton(
|
||||||
context,
|
context,
|
||||||
'Settings',
|
'Settings',
|
||||||
|
|
|
@ -3,24 +3,18 @@ import 'package:result_monad/result_monad.dart';
|
||||||
import '../../models/exec_error.dart';
|
import '../../models/exec_error.dart';
|
||||||
import '../../models/group_data.dart';
|
import '../../models/group_data.dart';
|
||||||
|
|
||||||
class IGroupsRepo {
|
abstract class IGroupsRepo {
|
||||||
void addAllGroups(List<GroupData> groups) {
|
void addAllGroups(List<GroupData> groups);
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearMyGroups() {
|
void clearMyGroups();
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GroupData> getMyGroups() {
|
void upsertGroup(GroupData group);
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<List<GroupData>, ExecError> getGroupsForUser(String id) {
|
void deleteGroup(GroupData group);
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool updateConnectionGroupData(String id, List<GroupData> currentGroups) {
|
List<GroupData> getMyGroups();
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
Result<List<GroupData>, ExecError> getGroupsForUser(String id);
|
||||||
|
|
||||||
|
bool updateConnectionGroupData(String id, List<GroupData> currentGroups);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,4 +40,16 @@ class MemoryGroupsRepo implements IGroupsRepo {
|
||||||
_groupsForConnection[id] = currentGroups;
|
_groupsForConnection[id] = currentGroups;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void upsertGroup(GroupData group) {
|
||||||
|
_myGroups.remove(group);
|
||||||
|
_myGroups.add(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void deleteGroup(GroupData group) {
|
||||||
|
_groupsForConnection.remove(group.id);
|
||||||
|
_myGroups.remove(group);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,47 @@ class GroupsClient extends FriendicaClient {
|
||||||
: ExecError(type: ErrorType.localError, message: error.toString()));
|
: ExecError(type: ErrorType.localError, message: error.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureResult<GroupData, ExecError> createGroup(String title) async {
|
||||||
|
_logger.finest(() => 'Creating group (Mastodon List) of name $title');
|
||||||
|
final url = 'https://$serverName/api/v1/lists';
|
||||||
|
final body = {
|
||||||
|
'title': title,
|
||||||
|
};
|
||||||
|
final result = await postUrl(
|
||||||
|
Uri.parse(url),
|
||||||
|
body,
|
||||||
|
headers: _headers,
|
||||||
|
).andThenSuccessAsync(
|
||||||
|
(data) async => GroupDataMastodonExtensions.fromJson(jsonDecode(data)));
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureResult<GroupData, ExecError> renameGroup(
|
||||||
|
String id, String title) async {
|
||||||
|
_logger.finest(() => 'Reanming group (Mastodon List) to name $title');
|
||||||
|
final url = 'https://$serverName/api/v1/lists/$id';
|
||||||
|
final body = {
|
||||||
|
'title': title,
|
||||||
|
};
|
||||||
|
final result = await putUrl(
|
||||||
|
Uri.parse(url),
|
||||||
|
body,
|
||||||
|
headers: _headers,
|
||||||
|
).andThenSuccessAsync((data) async {
|
||||||
|
final json = jsonDecode(data);
|
||||||
|
return GroupDataMastodonExtensions.fromJson(json);
|
||||||
|
});
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureResult<bool, ExecError> deleteGroup(GroupData groupData) async {
|
||||||
|
_logger.finest(
|
||||||
|
() => 'Reanming group (Mastodon List) to name ${groupData.name}');
|
||||||
|
final url = 'https://$serverName/api/v1/lists/${groupData.id}';
|
||||||
|
final result = await deleteUrl(Uri.parse(url), {}, headers: _headers);
|
||||||
|
return result.mapValue((_) => true).execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
FutureResult<List<GroupData>, ExecError> getMemberGroupsForConnection(
|
FutureResult<List<GroupData>, ExecError> getMemberGroupsForConnection(
|
||||||
String connectionId) async {
|
String connectionId) async {
|
||||||
_logger.finest(() =>
|
_logger.finest(() =>
|
||||||
|
|
|
@ -3,16 +3,6 @@ class GroupData {
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is GroupData &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
id == other.id &&
|
|
||||||
name == other.name;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => id.hashCode ^ name.hashCode;
|
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
GroupData(this.id, this.name);
|
GroupData(this.id, this.name);
|
||||||
|
@ -21,4 +11,12 @@ class GroupData {
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'GroupData{id: $id, name: $name}';
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ import 'screens/editor.dart';
|
||||||
import 'screens/follow_request_adjudication_screen.dart';
|
import 'screens/follow_request_adjudication_screen.dart';
|
||||||
import 'screens/gallery_browsers_screen.dart';
|
import 'screens/gallery_browsers_screen.dart';
|
||||||
import 'screens/gallery_screen.dart';
|
import 'screens/gallery_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/home.dart';
|
||||||
import 'screens/interactions_viewer_screen.dart';
|
import 'screens/interactions_viewer_screen.dart';
|
||||||
import 'screens/message_thread_screen.dart';
|
import 'screens/message_thread_screen.dart';
|
||||||
|
@ -34,6 +37,7 @@ class ScreenPaths {
|
||||||
static String notifications = '/notifications';
|
static String notifications = '/notifications';
|
||||||
static String signin = '/signin';
|
static String signin = '/signin';
|
||||||
static String manageProfiles = '/switchProfiles';
|
static String manageProfiles = '/switchProfiles';
|
||||||
|
static String groupManagement = '/group_management';
|
||||||
static String signup = '/signup';
|
static String signup = '/signup';
|
||||||
static String userProfile = '/user_profile';
|
static String userProfile = '/user_profile';
|
||||||
static String userPosts = '/user_posts';
|
static String userPosts = '/user_posts';
|
||||||
|
@ -120,6 +124,23 @@ final appRouter = GoRouter(
|
||||||
builder: (context, state) =>
|
builder: (context, state) =>
|
||||||
MessageThreadScreen(parentThreadId: state.queryParams['uri']!),
|
MessageThreadScreen(parentThreadId: state.queryParams['uri']!),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
name: ScreenPaths.groupManagement,
|
||||||
|
path: ScreenPaths.groupManagement,
|
||||||
|
builder: (context, state) => const GroupManagementScreen(),
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: 'show/:id',
|
||||||
|
builder: (context, state) => GroupEditorScreen(
|
||||||
|
groupId: state.params['id']!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: 'new',
|
||||||
|
builder: (context, state) => GroupCreateScreen(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: ScreenPaths.settings,
|
path: ScreenPaths.settings,
|
||||||
name: ScreenPaths.settings,
|
name: ScreenPaths.settings,
|
||||||
|
|
75
lib/screens/group_create_screen.dart
Normal file
75
lib/screens/group_create_screen.dart
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../controls/padding.dart';
|
||||||
|
import '../controls/standard_appbar.dart';
|
||||||
|
import '../services/connections_manager.dart';
|
||||||
|
import '../utils/active_profile_selector.dart';
|
||||||
|
import '../utils/snackbar_builder.dart';
|
||||||
|
|
||||||
|
class GroupCreateScreen extends StatefulWidget {
|
||||||
|
GroupCreateScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GroupCreateScreen> createState() => _GroupCreateScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GroupCreateScreenState extends State<GroupCreateScreen> {
|
||||||
|
final groupTextController = TextEditingController();
|
||||||
|
|
||||||
|
Future<void> createGroup(ConnectionsManager manager) async {
|
||||||
|
if (groupTextController.text.isEmpty) {
|
||||||
|
buildSnackbar(context, "Group name can't be empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = await manager.createGroup(groupTextController.text);
|
||||||
|
if (context.mounted) {
|
||||||
|
result.match(
|
||||||
|
onSuccess: (_) => context.canPop() ? context.pop() : null,
|
||||||
|
onError: (error) =>
|
||||||
|
buildSnackbar(context, 'Error trying to create new group: $error'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final manager = context
|
||||||
|
.watch<ActiveProfileSelector<ConnectionsManager>>()
|
||||||
|
.activeEntry
|
||||||
|
.value;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: StandardAppBar.build(
|
||||||
|
context,
|
||||||
|
'New group',
|
||||||
|
withHome: false,
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
controller: groupTextController,
|
||||||
|
textCapitalization: TextCapitalization.sentences,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Group Name',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(),
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const VerticalPadding(),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => createGroup(manager),
|
||||||
|
child: const Text('Create'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
174
lib/screens/group_editor_screen.dart
Normal file
174
lib/screens/group_editor_screen.dart
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:result_monad/result_monad.dart';
|
||||||
|
|
||||||
|
import '../controls/padding.dart';
|
||||||
|
import '../controls/responsive_max_width.dart';
|
||||||
|
import '../controls/standard_appbar.dart';
|
||||||
|
import '../globals.dart';
|
||||||
|
import '../models/group_data.dart';
|
||||||
|
import '../services/connections_manager.dart';
|
||||||
|
import '../utils/active_profile_selector.dart';
|
||||||
|
import '../utils/snackbar_builder.dart';
|
||||||
|
|
||||||
|
class GroupEditorScreen extends StatefulWidget {
|
||||||
|
final String groupId;
|
||||||
|
|
||||||
|
GroupEditorScreen({super.key, required this.groupId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GroupEditorScreen> createState() => _GroupEditorScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GroupEditorScreenState extends State<GroupEditorScreen> {
|
||||||
|
final groupTextController = TextEditingController();
|
||||||
|
var processingUpdate = false;
|
||||||
|
var allowNameEditing = false;
|
||||||
|
late GroupData groupData;
|
||||||
|
|
||||||
|
Future<void> updateGroupName(
|
||||||
|
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?');
|
||||||
|
if (context.mounted && confirm == true) {
|
||||||
|
await manager.renameGroup(widget.groupId, updated).match(
|
||||||
|
onSuccess: (updatedGroupData) {
|
||||||
|
groupData = updatedGroupData;
|
||||||
|
setState(() {
|
||||||
|
allowNameEditing = false;
|
||||||
|
});
|
||||||
|
}, onError: (error) {
|
||||||
|
if (mounted) {
|
||||||
|
buildSnackbar(context, 'Error renaming group: $error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
groupTextController.text = groupData.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processingUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteGroup(ConnectionsManager manager) async {
|
||||||
|
final confirm = await showYesNoDialog(context,
|
||||||
|
"Permanently delete group ${groupData.name}? This can't be undone.");
|
||||||
|
if (context.mounted && confirm == true) {
|
||||||
|
await manager.deleteGroup(groupData).match(
|
||||||
|
onSuccess: (_) => context.canPop() ? context.pop() : null,
|
||||||
|
onError: (error) =>
|
||||||
|
buildSnackbar(context, 'Error trying to delete group: $error'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final manager =
|
||||||
|
getIt<ActiveProfileSelector<ConnectionsManager>>().activeEntry.value;
|
||||||
|
groupData = manager
|
||||||
|
.getMyGroups()
|
||||||
|
.where(
|
||||||
|
(g) => g.id == widget.groupId,
|
||||||
|
)
|
||||||
|
.first;
|
||||||
|
groupTextController.text = groupData.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final manager = context
|
||||||
|
.watch<ActiveProfileSelector<ConnectionsManager>>()
|
||||||
|
.activeEntry
|
||||||
|
.value;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: StandardAppBar.build(
|
||||||
|
context,
|
||||||
|
'Group Editor',
|
||||||
|
withHome: false,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => deleteGroup(manager),
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
manager.refreshGroups();
|
||||||
|
},
|
||||||
|
child: ResponsiveMaxWidth(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
enabled: allowNameEditing,
|
||||||
|
readOnly: !allowNameEditing,
|
||||||
|
onEditingComplete: () async {
|
||||||
|
if (processingUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateGroupName(context, manager);
|
||||||
|
},
|
||||||
|
onTapOutside: (_) async {
|
||||||
|
if (processingUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateGroupName(context, manager);
|
||||||
|
},
|
||||||
|
controller: groupTextController,
|
||||||
|
textCapitalization: TextCapitalization.sentences,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Group Name',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(),
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HorizontalPadding(),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (allowNameEditing) {
|
||||||
|
groupTextController.text = groupData.name;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
allowNameEditing = !allowNameEditing;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.edit),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.separated(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text("User"),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (_, __) => const Divider(),
|
||||||
|
itemCount: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
58
lib/screens/group_management_screen.dart
Normal file
58
lib/screens/group_management_screen.dart
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../controls/responsive_max_width.dart';
|
||||||
|
import '../controls/standard_appbar.dart';
|
||||||
|
import '../routes.dart';
|
||||||
|
import '../services/connections_manager.dart';
|
||||||
|
import '../utils/active_profile_selector.dart';
|
||||||
|
|
||||||
|
class GroupManagementScreen extends StatelessWidget {
|
||||||
|
const GroupManagementScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final manager = context
|
||||||
|
.watch<ActiveProfileSelector<ConnectionsManager>>()
|
||||||
|
.activeEntry
|
||||||
|
.value;
|
||||||
|
final groups = manager.getMyGroups();
|
||||||
|
return Scaffold(
|
||||||
|
appBar: StandardAppBar.build(
|
||||||
|
context,
|
||||||
|
'Groups Management',
|
||||||
|
withHome: false,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => context.push(
|
||||||
|
'${ScreenPaths.groupManagement}/new',
|
||||||
|
),
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
manager.refreshGroups();
|
||||||
|
},
|
||||||
|
child: ResponsiveMaxWidth(
|
||||||
|
child: ListView.separated(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final group = groups[index];
|
||||||
|
return ListTile(
|
||||||
|
title: Text(group.name),
|
||||||
|
onTap: () => context.push(
|
||||||
|
'${ScreenPaths.groupManagement}/show/${group.id}'),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (_, __) => const Divider(),
|
||||||
|
itemCount: groups.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -194,6 +194,41 @@ class ConnectionsManager extends ChangeNotifier {
|
||||||
return myGroups;
|
return myGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureResult<GroupData, ExecError> createGroup(String newName) async {
|
||||||
|
final result = await GroupsClient(getIt<AccountsService>().currentProfile)
|
||||||
|
.createGroup(newName)
|
||||||
|
.withResultAsync((newGroup) async {
|
||||||
|
groupsRepo.upsertGroup(newGroup);
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureResult<GroupData, ExecError> renameGroup(
|
||||||
|
String id, String newName) async {
|
||||||
|
final result = await GroupsClient(getIt<AccountsService>().currentProfile)
|
||||||
|
.renameGroup(id, newName)
|
||||||
|
.withResultAsync((renamedGroup) async {
|
||||||
|
groupsRepo.upsertGroup(renamedGroup);
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
|
FutureResult<bool, ExecError> deleteGroup(GroupData groupData) async {
|
||||||
|
final result = await GroupsClient(getIt<AccountsService>().currentProfile)
|
||||||
|
.deleteGroup(groupData)
|
||||||
|
.withResultAsync((_) async {
|
||||||
|
groupsRepo.deleteGroup(groupData);
|
||||||
|
notifyListeners();
|
||||||
|
});
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshGroups() {
|
||||||
|
_updateMyGroups(true);
|
||||||
|
}
|
||||||
|
|
||||||
Result<List<GroupData>, ExecError> getGroupsForUser(String id) {
|
Result<List<GroupData>, ExecError> getGroupsForUser(String id) {
|
||||||
final result = groupsRepo.getGroupsForUser(id);
|
final result = groupsRepo.getGroupsForUser(id);
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
|
|
|
@ -948,10 +948,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: result_monad
|
name: result_monad
|
||||||
sha256: "8f7720b9d517dbb54d612e2f6c6c4f409d51374f0d9ff9749dfcb0e0c6ab2fd4"
|
sha256: "59e65e969f93c8aff18104f36233b0fd102a096d6501d3515e2a80cd67f3565a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.1.0"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -38,7 +38,7 @@ dependencies:
|
||||||
network_to_file_image: ^4.0.1
|
network_to_file_image: ^4.0.1
|
||||||
path: ^1.8.2
|
path: ^1.8.2
|
||||||
provider: ^6.0.4
|
provider: ^6.0.4
|
||||||
result_monad: ^2.0.2
|
result_monad: ^2.1.0
|
||||||
scrollable_positioned_list: ^0.3.5
|
scrollable_positioned_list: ^0.3.5
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
sqlite3: ^1.9.1
|
sqlite3: ^1.9.1
|
||||||
|
|
Loading…
Reference in a new issue