1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 04:49:21 +00:00

Can request to join a Forez group

This commit is contained in:
Pierre HUBERT 2021-04-23 19:32:34 +02:00
parent 0cd6ed284b
commit d178e8b1c3
8 changed files with 122 additions and 23 deletions

View File

@ -0,0 +1,19 @@
import 'package:comunic/helpers/preferences_helper.dart';
/// Forez group helper
///
/// Contains the ID of the currently selected Forez group
///
/// @author Pierre Hubert
class ForezGroupHelper {
static Future<void> setId(int groupID) async {
(await PreferencesHelper.getInstance())
.setInt(PreferencesKeyList.FOREZ_GROUP, groupID);
}
static Future<int> getId() async {
return (await PreferencesHelper.getInstance())
.getInt(PreferencesKeyList.FOREZ_GROUP);
}
}

View File

@ -15,7 +15,7 @@ const _JOIN_GROUP_KEY_ID = 1;
List<Widget> buildTour(TourRouteState state) { List<Widget> buildTour(TourRouteState state) {
if (!state.pubKeys.containsKey(_JOIN_GROUP_KEY_ID)) if (!state.pubKeys.containsKey(_JOIN_GROUP_KEY_ID))
state.pubKeys[_JOIN_GROUP_KEY_ID] = GlobalKey(); state.pubKeys[_JOIN_GROUP_KEY_ID] = GlobalKey<JoinGroupPaneBodyState>();
return [ return [
FirstTourPane( FirstTourPane(

View File

@ -1,8 +1,13 @@
import 'package:comunic/forez/helpers/forez_group_helper.dart';
import 'package:comunic/helpers/forez_groups_helper.dart'; import 'package:comunic/helpers/forez_groups_helper.dart';
import 'package:comunic/helpers/groups_helper.dart';
import 'package:comunic/models/group.dart'; import 'package:comunic/models/group.dart';
import 'package:comunic/ui/dialogs/alert_dialog.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart';
import 'package:comunic/ui/widgets/tour/presentation_pane.dart'; import 'package:comunic/ui/widgets/tour/presentation_pane.dart';
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/log_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
/// Ask the user to join a Forez group /// Ask the user to join a Forez group
@ -12,14 +17,16 @@ import 'package:flutter/material.dart';
class JoinGroupPane extends PresentationPane { class JoinGroupPane extends PresentationPane {
JoinGroupPane({ JoinGroupPane({
@required Function() onUpdated, @required Function() onUpdated,
@required GlobalKey key, @required GlobalKey<JoinGroupPaneBodyState> key,
}) : super( }) : super(
icon: Icons.login, icon: Icons.login,
title: tr("Join a group"), title: tr("Join a Forez group"),
child: (c) => _JoinGroupPaneBody( child: (c) => _JoinGroupPaneBody(
key: key, key: key,
onUpdated: onUpdated, onUpdated: onUpdated,
), ),
canGoNext: key?.currentState?.canGoNext ?? false,
onTapNext: (c) => key.currentState.validateChoice(),
); );
} }
@ -33,14 +40,20 @@ class _JoinGroupPaneBody extends StatefulWidget {
super(key: key); super(key: key);
@override @override
__JoinGroupPaneBodyState createState() => __JoinGroupPaneBodyState(); JoinGroupPaneBodyState createState() => JoinGroupPaneBodyState();
} }
class __JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> { class JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> {
List<Group> _groups; List<Group> _groups;
int _currChoice;
bool get canGoNext => _currChoice != null && _currChoice > 0;
Group get _currGroup => _groups.firstWhere((e) => e.id == _currChoice);
Future<void> _load() async { Future<void> _load() async {
_groups = await ForezGroupsHelper.getForezGroups(); _groups = await ForezGroupsHelper.getForezGroups();
_currChoice = _groups[0].id;
} }
@override @override
@ -49,18 +62,60 @@ class __JoinGroupPaneBodyState extends State<_JoinGroupPaneBody> {
onBuild: onBuild, onBuild: onBuild,
errorMessage: tr("Failed to load the list of Forez groups!")); errorMessage: tr("Failed to load the list of Forez groups!"));
List<Widget> get _initialWidgets => [ Widget onBuild() => ConstrainedBox(
Text(tr("Please choose now the Forez group you want to join...")), constraints: BoxConstraints(maxWidth: 300),
]; child: Column(
children: [
Text(tr("Please choose now the Forez group you want to join...")),
]..addAll(_groups.map((e) => RadioListTile(
value: e.id,
groupValue: _currChoice,
onChanged: (v) => setState(() => _currChoice = _currChoice),
title: Text(e.name),
subtitle: Text(e.membershipText),
))),
),
);
Widget onBuild() => Flexible( Future<bool> validateChoice() async {
child: ListView.builder( try {
itemCount: _initialWidgets.length + _groups.length, switch (_currGroup.membershipLevel) {
itemBuilder: (c, i) { case GroupMembershipLevel.VISITOR:
if (i < _initialWidgets.length) return _initialWidgets[i]; if (!await GroupsHelper.sendRequest(_currGroup.id))
throw Exception("Failed to send group membership request!");
break;
final group = _groups[i - _initialWidgets.length]; case GroupMembershipLevel.INVITED:
return ListTile(); if (!await GroupsHelper.respondInvitation(_currGroup.id, true))
}, throw Exception(
)); "Failed to respond to group membership invitation!");
break;
case GroupMembershipLevel.PENDING:
break;
case GroupMembershipLevel.ADMINISTRATOR:
case GroupMembershipLevel.MODERATOR:
case GroupMembershipLevel.MEMBER:
break;
}
// Check if the user can not access yet the group
if ((_currGroup.membershipLevel == GroupMembershipLevel.VISITOR &&
_currGroup.registrationLevel != GroupRegistrationLevel.OPEN) ||
_currGroup.membershipLevel == GroupMembershipLevel.PENDING) {
await alert(context,
tr("You can not access this group yet, please wait for a member of the group to accept your request. Hopefully this will not be too long. Please check back soon!"));
return false;
}
await ForezGroupHelper.setId(_currGroup.id);
return true;
} catch (e, s) {
logError(e, s);
snack(context, tr("Failed to register to group!"));
return false;
}
}
} }

View File

@ -141,9 +141,9 @@ class GroupsHelper {
} }
/// Perform a simple membership request /// Perform a simple membership request
Future<bool> _simpleMembershipRequest(int groupID, String uri, static Future<bool> _simpleMembershipRequest(int groupID, String uri,
{Map<String, String> args}) async => {Map<String, String> args}) async =>
(await (APIRequest(uri: uri, needLogin: true) (await (APIRequest.withLogin(uri)
..addInt("id", groupID) ..addInt("id", groupID)
..addArgs(args == null ? Map() : args)) ..addArgs(args == null ? Map() : args))
.exec()) .exec())
@ -158,11 +158,11 @@ class GroupsHelper {
_simpleMembershipRequest(groupID, "groups/cancel_request"); _simpleMembershipRequest(groupID, "groups/cancel_request");
/// Send a new membership request /// Send a new membership request
Future<bool> sendRequest(int groupID) async => static Future<bool> sendRequest(int groupID) async =>
_simpleMembershipRequest(groupID, "groups/send_request"); _simpleMembershipRequest(groupID, "groups/send_request");
/// Respond to a group membership invitation /// Respond to a group membership invitation
Future<bool> respondInvitation(int groupID, bool accept) async => static Future<bool> respondInvitation(int groupID, bool accept) async =>
_simpleMembershipRequest(groupID, "groups/respond_invitation", args: { _simpleMembershipRequest(groupID, "groups/respond_invitation", args: {
"accept": accept ? "true" : "false", "accept": accept ? "true" : "false",
}); });

View File

@ -15,6 +15,7 @@ enum PreferencesKeyList {
SHOW_PERFORMANCE_OVERLAY, SHOW_PERFORMANCE_OVERLAY,
PUSH_NOTIFICATIONS_STATUS, PUSH_NOTIFICATIONS_STATUS,
IS_TOUR_SEEN, IS_TOUR_SEEN,
FOREZ_GROUP,
} }
const _PreferenceKeysName = { const _PreferenceKeysName = {
@ -25,6 +26,7 @@ const _PreferenceKeysName = {
PreferencesKeyList.SHOW_PERFORMANCE_OVERLAY: "perfs_overlay", PreferencesKeyList.SHOW_PERFORMANCE_OVERLAY: "perfs_overlay",
PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS: "push_notifications_status", PreferencesKeyList.PUSH_NOTIFICATIONS_STATUS: "push_notifications_status",
PreferencesKeyList.IS_TOUR_SEEN: "is_tour_seen", PreferencesKeyList.IS_TOUR_SEEN: "is_tour_seen",
PreferencesKeyList.FOREZ_GROUP: "forez_group",
}; };
class PreferencesHelper { class PreferencesHelper {

View File

@ -1,3 +1,4 @@
import 'package:comunic/utils/intl_utils.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
/// Group information /// Group information
@ -71,6 +72,25 @@ class Group implements Comparable<Group> {
(membershipLevel == GroupMembershipLevel.MEMBER && (membershipLevel == GroupMembershipLevel.MEMBER &&
postCreationLevel == GroupPostCreationLevel.MEMBERS); postCreationLevel == GroupPostCreationLevel.MEMBERS);
String get membershipText {
switch (membershipLevel) {
case GroupMembershipLevel.ADMINISTRATOR:
return tr("Administrator");
case GroupMembershipLevel.MODERATOR:
return tr("Moderator");
case GroupMembershipLevel.MEMBER:
return tr("Member");
case GroupMembershipLevel.INVITED:
return tr("Invited");
case GroupMembershipLevel.PENDING:
return tr("Requested");
case GroupMembershipLevel.VISITOR:
return tr("Visitor");
}
throw new Exception("Unreachable statement!");
}
@override @override
int compareTo(Group other) => id.compareTo(other.id); int compareTo(Group other) => id.compareTo(other.id);
} }

View File

@ -87,7 +87,7 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
message: tr("Do you really want to reject this invitation?"))) message: tr("Do you really want to reject this invitation?")))
return; return;
if (!await GroupsHelper().respondInvitation(_id, accept)) { if (!await GroupsHelper.respondInvitation(_id, accept)) {
showSimpleSnack(context, tr("Could not respond to your invitation!")); showSimpleSnack(context, tr("Could not respond to your invitation!"));
if (this.widget.onError != null) this.widget.onError(); if (this.widget.onError != null) this.widget.onError();
} else { } else {
@ -147,7 +147,7 @@ class _GroupMembershipWidgetState extends SafeState<GroupMembershipWidget> {
/// Create new membership request /// Create new membership request
void _requestMembership() async { void _requestMembership() async {
if (!await GroupsHelper().sendRequest(_id)) { if (!await GroupsHelper.sendRequest(_id)) {
showSimpleSnack(context, tr("Could not send your membership request!")); showSimpleSnack(context, tr("Could not send your membership request!"));
if (this.widget.onError != null) this.widget.onError(); if (this.widget.onError != null) this.widget.onError();
} else { } else {

View File

@ -46,6 +46,9 @@ class LoginRoutesTheme extends StatelessWidget {
accentColor: Colors.white, accentColor: Colors.white,
hintColor: Colors.white, hintColor: Colors.white,
textTheme: TextTheme(subtitle1: TextStyle(color: Colors.white)), textTheme: TextTheme(subtitle1: TextStyle(color: Colors.white)),
radioTheme: RadioThemeData(
fillColor: MaterialStateProperty.all(Colors.white),
),
colorScheme: ColorScheme( colorScheme: ColorScheme(
primary: Colors.white, primary: Colors.white,
primaryVariant: Colors.white, primaryVariant: Colors.white,