From f7ee66e439d84e5c7c91b2c40c76167d8a9a2270 Mon Sep 17 00:00:00 2001 From: skazkiful <30957783+skazkiful@users.noreply.github.com> Date: Wed, 7 Dec 2022 14:49:21 +0200 Subject: [PATCH] Implement `CallMember` redialing (#241, #233) --- CHANGELOG.md | 4 ++ assets/l10n/en-US.ftl | 1 + assets/l10n/ru-RU.ftl | 1 + .../call/RedialChatCallMember.graphql | 27 +++++++++++ lib/domain/repository/call.dart | 4 ++ lib/domain/service/call.dart | 12 ++++- lib/provider/gql/components/call.dart | 46 +++++++++++++++++++ lib/provider/gql/exceptions.dart | 31 +++++++++++++ lib/store/call.dart | 4 ++ lib/ui/page/call/participant/controller.dart | 15 ++++++ lib/ui/page/call/participant/view.dart | 4 +- 11 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 lib/api/backend/graphql/mutation/call/RedialChatCallMember.graphql diff --git a/CHANGELOG.md b/CHANGELOG.md index 86dbf1c3686..635504714ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ All user visible changes to this project will be documented in this file. This p - Searching. ([#206], [#205]) - Home page: - Quick status changing menu. ([#204], [#203]) + - Media panel: + - Participants redialing. ([#241], [#233]) ### Changed @@ -73,6 +75,8 @@ All user visible changes to this project will be documented in this file. This p [#217]: /../../pull/217 [#218]: /../../pull/218 [#221]: /../../pull/221 +[#233]: /../../issues/233 +[#241]: /../../pull/241 diff --git a/assets/l10n/en-US.ftl b/assets/l10n/en-US.ftl index e8b8ec780d9..9f8ccf32546 100644 --- a/assets/l10n/en-US.ftl +++ b/assets/l10n/en-US.ftl @@ -469,6 +469,7 @@ label_offline = Offline label_online = Online label_or_register = or register label_outgoing_call = Outgoing call +label_participant_redial_successfully = Participant redialed label_participants = Participants label_participants_added_successfully = Participants successfully added label_password = Password diff --git a/assets/l10n/ru-RU.ftl b/assets/l10n/ru-RU.ftl index 564963480d6..df090fb0409 100644 --- a/assets/l10n/ru-RU.ftl +++ b/assets/l10n/ru-RU.ftl @@ -491,6 +491,7 @@ label_offline = Офлайн label_online = Онлайн label_or_register = или регистрация label_outgoing_call = Исходящий звонок +label_participant_redial_successfully = Участник перенабран label_participants = Участники label_participants_added_successfully = Участники успешно добавлены label_password = Пароль diff --git a/lib/api/backend/graphql/mutation/call/RedialChatCallMember.graphql b/lib/api/backend/graphql/mutation/call/RedialChatCallMember.graphql new file mode 100644 index 00000000000..a011402a3f4 --- /dev/null +++ b/lib/api/backend/graphql/mutation/call/RedialChatCallMember.graphql @@ -0,0 +1,27 @@ +# Copyright © 2022 IT ENGINEERING MANAGEMENT INC, +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License v3.0 as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License v3.0 for +# more details. +# +# You should have received a copy of the GNU Affero General Public License v3.0 +# along with this program. If not, see +# . + +mutation RedialChatCallMember($chatId: ChatId!, $memberId: UserId!) { + redialChatCallMember(chatId: $chatId, memberId: $memberId) { + __typename + ... on ChatCallEventsVersioned { + ...ChatCallEventsVersioned + } + ... on RedialChatCallMemberError { + code + } + } +} diff --git a/lib/domain/repository/call.dart b/lib/domain/repository/call.dart index 530b58a8a3e..23fd07f17a2 100644 --- a/lib/domain/repository/call.dart +++ b/lib/domain/repository/call.dart @@ -82,6 +82,10 @@ abstract class AbstractCallRepository { ChatName? groupName, ); + /// Redials a [User] who left or declined the ongoing [ChatCall] in the + /// specified [Chat]-group by the authenticated [MyUser]. + Future redialChatCallMember(ChatId chatId, UserId memberId); + /// Generates the [ChatCallCredentials] for a [Chat] identified by the /// provided [id]. /// diff --git a/lib/domain/service/call.dart b/lib/domain/service/call.dart index de01234d418..090f55298b6 100644 --- a/lib/domain/service/call.dart +++ b/lib/domain/service/call.dart @@ -211,9 +211,11 @@ class CallService extends DisposableService { if (deviceId != null) { await _callsRepo.leave(chatId, deviceId); - _callsRepo.remove(chatId); + } else { + await _callsRepo.decline(chatId); } + _callsRepo.remove(chatId); WebUtils.removeCall(chatId); } @@ -289,6 +291,14 @@ class CallService extends DisposableService { } } + /// Redials a [User] who left or declined the ongoing [ChatCall] in the + /// specified [Chat]-group by the authenticated [MyUser]. + Future redialChatCallMember(ChatId chatId, UserId memberId) async { + if (_callsRepo.contains(chatId)) { + await _callsRepo.redialChatCallMember(chatId, memberId); + } + } + /// Moves an ongoing [ChatCall] in a [Chat]-dialog to a newly created /// [Chat]-group, optionally adding new members. Future transformDialogCallIntoGroupCall( diff --git a/lib/provider/gql/components/call.dart b/lib/provider/gql/components/call.dart index f66d126b410..f823b61edab 100644 --- a/lib/provider/gql/components/call.dart +++ b/lib/provider/gql/components/call.dart @@ -408,6 +408,52 @@ abstract class CallGraphQlMixin { as ChatCallEventsVersionedMixin?); } + /// Redials a [User] who left or declined the ongoing [ChatCall] in the + /// specified [Chat]-group by the authenticated [MyUser]. + /// + /// For using this mutation the authenticated [MyUser] must be a member of the + /// ongoing [ChatCall]. + /// + /// Redialed [User] should see the [ChatCall.answered] indicator as `false`, + /// and the ongoing [ChatCall] appearing in his [incomingCallsTopEvents] + /// again. + /// + /// ### Authentication + /// + /// Mandatory. + /// + /// ### Result + /// + /// One of the following [ChatCallEvent]s may be produced on success: + /// - [EventChatCallMemberRedialed]. + /// + /// ### Idempotent + /// + /// Succeeds as no-op (and returns no [ChatEvent]) if the redialed [User] + /// didn't decline or leave the [ChatCall] yet, or has been redialed already. + Future redialChatCallMember( + ChatId chatId, + UserId memberId, + ) async { + final variables = RedialChatCallMemberArguments( + chatId: chatId, + memberId: memberId, + ); + final QueryResult result = await client.mutate( + MutationOptions( + operationName: 'RedialChatCallMember', + document: RedialChatCallMemberMutation(variables: variables).document, + variables: variables.toJson(), + ), + onException: (data) => RedialChatCallMemberException( + (RedialChatCallMember$Mutation.fromJson(data).redialChatCallMember + as RedialChatCallMember$Mutation$RedialChatCallMember$RedialChatCallMemberError) + .code), + ); + return (RedialChatCallMember$Mutation.fromJson(result.data!) + .redialChatCallMember as ChatCallEventsVersionedMixin?); + } + /// Moves an ongoing [ChatCall] in a [Chat]-dialog to a newly created /// [Chat]-group, optionally adding new members. /// diff --git a/lib/provider/gql/exceptions.dart b/lib/provider/gql/exceptions.dart index 2e8a5ce5a07..042f3c30716 100644 --- a/lib/provider/gql/exceptions.dart +++ b/lib/provider/gql/exceptions.dart @@ -998,6 +998,37 @@ class ToggleChatCallHandException } } +/// Exception of `Mutation.redialChatCallMember` described in the [code]. +class RedialChatCallMemberException + with LocalizedExceptionMixin + implements Exception { + const RedialChatCallMemberException(this.code); + + /// Reason of why the mutation has failed. + final RedialChatCallMemberErrorCode code; + + @override + String toString() => 'RedialChatCallMemberException($code)'; + + @override + String toMessage() { + switch (code) { + case RedialChatCallMemberErrorCode.notCallMember: + return 'err_not_call_member'.l10n; + case RedialChatCallMemberErrorCode.noCall: + return 'err_call_not_found'.l10n; + case RedialChatCallMemberErrorCode.unknownChat: + return 'err_unknown_chat'.l10n; + case RedialChatCallMemberErrorCode.notChatMember: + return 'err_not_member'.l10n; + case RedialChatCallMemberErrorCode.notGroup: + return 'err_contact_not_group'.l10n; + case RedialChatCallMemberErrorCode.artemisUnknown: + return 'err_unknown'.l10n; + } + } +} + /// Exception of `Mutation.createChatDirectLink` described in the [code]. class CreateChatDirectLinkException with LocalizedExceptionMixin diff --git a/lib/store/call.dart b/lib/store/call.dart index 94a8c4966e6..273b4f62cd8 100644 --- a/lib/store/call.dart +++ b/lib/store/call.dart @@ -134,6 +134,10 @@ class CallRepository implements AbstractCallRepository { Future toggleHand(ChatId chatId, bool raised) => _graphQlProvider.toggleChatCallHand(chatId, raised); + @override + Future redialChatCallMember(ChatId chatId, UserId memberId) => + _graphQlProvider.redialChatCallMember(chatId, memberId); + @override Future transformDialogCallIntoGroupCall( ChatId chatId, diff --git a/lib/ui/page/call/participant/controller.dart b/lib/ui/page/call/participant/controller.dart index 49077d4539d..176a3905b6d 100644 --- a/lib/ui/page/call/participant/controller.dart +++ b/lib/ui/page/call/participant/controller.dart @@ -28,6 +28,7 @@ import '/l10n/l10n.dart'; import '/provider/gql/exceptions.dart' show AddChatMemberException, + RedialChatCallMemberException, RemoveChatMemberException, TransformDialogCallIntoGroupCallException; import '/util/message_popup.dart'; @@ -185,6 +186,20 @@ class ParticipantController extends GetxController { } } + /// Redials by specified [UserId] who left or declined the ongoing [ChatCall]. + Future redialChatCallMember(UserId memberId) async { + MessagePopup.success('label_participant_redial_successfully'.l10n); + + try { + await _callService.redialChatCallMember(chatId.value, memberId); + } on RedialChatCallMemberException catch (e) { + MessagePopup.error(e); + } catch (e) { + MessagePopup.error(e); + rethrow; + } + } + /// Fetches the [chat]. void _fetchChat() async { chat.value = null; diff --git a/lib/ui/page/call/participant/view.dart b/lib/ui/page/call/participant/view.dart index bb381faa6b5..08e466550ad 100644 --- a/lib/ui/page/call/participant/view.dart +++ b/lib/ui/page/call/participant/view.dart @@ -309,9 +309,7 @@ class ParticipantView extends StatelessWidget { color: Theme.of(context).colorScheme.secondary, type: MaterialType.circle, child: InkWell( - onTap: () { - // TODO: Redial the provided [user]. - }, + onTap: () => c.redialChatCallMember(user.id), borderRadius: BorderRadius.circular(60), child: SizedBox( width: 30,