From 71efc1fb9bd27ce3d1cb7ab824778607db63ffc6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 Feb 2019 09:42:35 +0100 Subject: [PATCH 01/13] Finish moving to Github #1 --- README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index eb1624cc..a88fda34 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,27 @@ OX Talk is a mail based chat app. This app provides the user interface for an IMAP / SMTP based chat on Android and iOS. -## Relevant information +- **Android state:** Currently in development +- **iOS state:** Pending + +## Information - [Documentation](https://confluence-public.open-xchange.com/display/COIPublic/OX+Talk+Mobile+App) - The IMAP / SMTP interactions are managed by the [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) ## Requirements -- Flutter 1.0 is used +- Flutter 1.0 is used (if problems occur try the [Flutter Dev Channel](https://github.com/flutter/flutter/wiki/Flutter-build-release-channels)) +-The [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) needs to be checked out right beside the OX Talk app (the repositories should be located in the same folder) and please follow the requirements given by that project -## Execution of the Flutter app -As for now (08.11.2018) it is required to execute the example app inside the project from console using ```flutter run --target-platform android-arm``` as the DCC is written as 32 bit program and Flutter is a -64 bit program (see https://github.com/flutter/flutter/issues/15530). When using an IDE use ```--target-platform android-arm``` as additional argument in your run configuration. +## Execution +- Build and run the project via your IDE / Flutter CLI ## Development -To be able to edit / extend the ox_talk app the following steps are important after checking out / altering the project: -- No special requirements +To be able to edit / extend this project the following steps are important: + +- Perform all actions mentioned under **Execution** +- Implement your changes +- Add tests and code for the test suite +- Create a pull request ### Flutter From 4c5ae7c992e2e3c7d567e04dc03ef6275ff0a9aa Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 Feb 2019 09:43:14 +0100 Subject: [PATCH 02/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a88fda34..888624cd 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ OX Talk is a mail based chat app. This app provides the user interface for an IM ## Requirements - Flutter 1.0 is used (if problems occur try the [Flutter Dev Channel](https://github.com/flutter/flutter/wiki/Flutter-build-release-channels)) --The [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) needs to be checked out right beside the OX Talk app (the repositories should be located in the same folder) and please follow the requirements given by that project +- The [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) needs to be checked out right beside the OX Talk app (the repositories should be located in the same folder) and please follow the requirements given by that project ## Execution - Build and run the project via your IDE / Flutter CLI From e7b1607c3f14a7167091dce0ddb3d38f55af42df Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Mon, 25 Feb 2019 13:20:12 +0100 Subject: [PATCH 03/13] Update libraries and clean up warnings #3 OT-115 --- lib/source/chat/messages_state.dart | 1 - lib/source/chatlist/chat_list_item.dart | 1 - lib/source/chatlist/create_chat.dart | 1 - lib/source/chatlist/create_group_chat.dart | 1 - lib/source/data/chat_list_repository.dart | 2 ++ lib/source/log/bloc_delegate.dart | 5 +++++ lib/source/login/login_bloc.dart | 2 ++ lib/source/main/root.dart | 1 - lib/source/profile/edit_user_settings.dart | 6 ------ pubspec.yaml | 17 +++++++++-------- 10 files changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/source/chat/messages_state.dart b/lib/source/chat/messages_state.dart index 22613dad..40fdd008 100644 --- a/lib/source/chat/messages_state.dart +++ b/lib/source/chat/messages_state.dart @@ -40,7 +40,6 @@ * for more details. */ -import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:meta/meta.dart'; import 'package:ox_talk/source/base/bloc_base_state.dart'; diff --git a/lib/source/chatlist/chat_list_item.dart b/lib/source/chatlist/chat_list_item.dart index 8871269e..2b52037f 100644 --- a/lib/source/chatlist/chat_list_item.dart +++ b/lib/source/chatlist/chat_list_item.dart @@ -47,7 +47,6 @@ import 'package:ox_talk/source/chat/chat_bloc.dart'; import 'package:ox_talk/source/chat/chat_event.dart'; import 'package:ox_talk/source/chat/chat_state.dart'; import 'package:ox_talk/source/widgets/avatar_list_item.dart'; -import 'package:ox_talk/source/utils/colors.dart'; class ChatListItem extends StatefulWidget { final int _chatId; diff --git a/lib/source/chatlist/create_chat.dart b/lib/source/chatlist/create_chat.dart index 9438b640..b2f632c4 100644 --- a/lib/source/chatlist/create_chat.dart +++ b/lib/source/chatlist/create_chat.dart @@ -81,7 +81,6 @@ class _CreateChatState extends State { ); } - @override Widget buildForm() { return BlocBuilder( bloc: _contactListBloc, diff --git a/lib/source/chatlist/create_group_chat.dart b/lib/source/chatlist/create_group_chat.dart index 4dce3084..2c61f2e6 100644 --- a/lib/source/chatlist/create_group_chat.dart +++ b/lib/source/chatlist/create_group_chat.dart @@ -94,7 +94,6 @@ class _CreateGroupChatState extends State { ); } - @override Widget buildForm() { return BlocBuilder( bloc: _contactListBloc, diff --git a/lib/source/data/chat_list_repository.dart b/lib/source/data/chat_list_repository.dart index 102d53fc..fc7c8abe 100644 --- a/lib/source/data/chat_list_repository.dart +++ b/lib/source/data/chat_list_repository.dart @@ -40,6 +40,8 @@ * for more details. */ +import 'dart:async'; + import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:ox_talk/source/data/repository.dart'; diff --git a/lib/source/log/bloc_delegate.dart b/lib/source/log/bloc_delegate.dart index 0dc8e772..2f782281 100644 --- a/lib/source/log/bloc_delegate.dart +++ b/lib/source/log/bloc_delegate.dart @@ -47,4 +47,9 @@ class DebugBlocDelegate implements BlocDelegate { void onTransition(Transition transition) { print(transition.toString()); } + + @override + void onError(Object error, StackTrace stacktrace) { + print("Error: $error (Stacktrace: $stacktrace)"); + } } diff --git a/lib/source/login/login_bloc.dart b/lib/source/login/login_bloc.dart index 8bdaa7d4..d90e5c34 100644 --- a/lib/source/login/login_bloc.dart +++ b/lib/source/login/login_bloc.dart @@ -40,6 +40,8 @@ * for more details. */ +import 'dart:async'; + import 'package:bloc/bloc.dart'; import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:ox_talk/source/data/config.dart'; diff --git a/lib/source/main/root.dart b/lib/source/main/root.dart index 4b7e7d17..56bfe766 100644 --- a/lib/source/main/root.dart +++ b/lib/source/main/root.dart @@ -44,7 +44,6 @@ import 'package:flutter/material.dart'; import 'package:ox_talk/source/base/base_root_child.dart'; import 'package:ox_talk/source/chatlist/chat_list.dart'; import 'package:ox_talk/source/contact/contact_list.dart'; -import 'package:ox_talk/source/maillist/mail_list.dart'; import 'package:ox_talk/source/profile/profile.dart'; class Root extends StatefulWidget { diff --git a/lib/source/profile/edit_user_settings.dart b/lib/source/profile/edit_user_settings.dart index 70dca87d..31bd4e96 100644 --- a/lib/source/profile/edit_user_settings.dart +++ b/lib/source/profile/edit_user_settings.dart @@ -69,17 +69,12 @@ class _EditUserSettingsState extends State with TickerProvider File _image; String _path = ""; - AnimationController _controller; //ImagePickerHandler _imagePicker; @override void initState() { super.initState(); _userBloc.dispatch(RequestUser()); - _controller = new AnimationController( - vsync: this, - duration: const Duration(milliseconds: 500), - ); //_imagePicker = new ImagePickerHandler(this, _controller); //_imagePicker.build(0xFFEE6969,0xFFFFFFFF,false); @@ -182,7 +177,6 @@ class _EditUserSettingsState extends State with TickerProvider ); } - @override userImage(File _newImage) { setState(() { _image = _newImage; diff --git a/pubspec.yaml b/pubspec.yaml index 9bbdc851..94f7783f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,16 +11,17 @@ dependencies: sdk: flutter flutter_localizations: sdk: flutter - bloc: ^0.8.0 - contacts_service: ^0.2.0 + bloc: ^0.9.3 + contacts_service: ^0.2.1 cupertino_icons: ^0.1.2 - date_format: ^1.0.5 - flutter_bloc: ^0.5.1 - fluttertoast: ^3.0.0 - rxdart: ^0.20.0 - #image_picker_ui: ^0.2.0 + date_format: ^1.0.6 + flutter_bloc: ^0.7.0 + fluttertoast: ^3.0.1 + rxdart: ^0.20.0 # ^0.21.0 exists but 0.20.0 is used for compatibility reasons with bloc: ^0.9.3 + image_cropper: ^1.0.0 + image_picker: ^0.5.0+3 open_file: ^1.2.2+2 - path_provider: ^0.4.1 + path_provider: ^0.5.0+1 permission_handler: ^3.0.0 shared_preferences: ^0.5.1+1 delta_chat_core: From 448b56e8505833a751c22b1e7b6cabe3b6e5c30f Mon Sep 17 00:00:00 2001 From: Boehrsi Date: Tue, 26 Feb 2019 09:14:14 +0100 Subject: [PATCH 04/13] DOCU Add images --- documentation/architecture.png | Bin 0 -> 11918 bytes documentation/architecture.txt | 17 +++++++++++++++++ documentation/communication-app-plugin.png | Bin 0 -> 21312 bytes documentation/communication-app-plugin.txt | 13 +++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 documentation/architecture.png create mode 100644 documentation/architecture.txt create mode 100644 documentation/communication-app-plugin.png create mode 100644 documentation/communication-app-plugin.txt diff --git a/documentation/architecture.png b/documentation/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..b4792194e3c0a91a4f4c39b6533b5c76400962e1 GIT binary patch literal 11918 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 "BloC" + "BloC" -> "UI / Widget" + + "BloC" -> "Plugin" + "BloC" -> "Repository / Data Object" + "Repository / Data Object" -> "BloC" + + "Repository / Data Object" -> "Plugin" + "Plugin" -> "Repository / Data Object" +} diff --git a/documentation/communication-app-plugin.png b/documentation/communication-app-plugin.png new file mode 100644 index 0000000000000000000000000000000000000000..34f34509c9e86564980acf6083ea19ecf3d3daeb GIT binary patch literal 21312 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 HwY&cpMd$wX literal 0 HcmV?d00001 diff --git a/documentation/communication-app-plugin.txt b/documentation/communication-app-plugin.txt new file mode 100644 index 00000000..1bf4a1a9 --- /dev/null +++ b/documentation/communication-app-plugin.txt @@ -0,0 +1,13 @@ +digraph G { + node [ + shape = polygon, + sides = 4, + style = filled, + fontname = "Helvetica-Outline" + ]; + "OX Talk App (Flutter)" -> "Delta Chat Core Plugin API (Dart)" + "Delta Chat Core Plugin API (Dart)" -> "Delta Chat Core Plugin Native Android API (Java/Kotlin)" + "Delta Chat Core Plugin API (Dart)" -> "Delta Chat Core Plugin Native iOS API (ObjC/Swift)" + "Delta Chat Core Plugin Native Android API (Java/Kotlin)" -> "Delta Chat Core IMAP/SMTP logic (C)" + "Delta Chat Core Plugin Native iOS API (ObjC/Swift)" -> "Delta Chat Core IMAP/SMTP logic (C)" +} From 17c3fdc34d01c789c6794a72c1a5e6a9bfd32a05 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 26 Feb 2019 10:05:02 +0100 Subject: [PATCH 05/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 888624cd..a420cf90 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OX Talk is a mail based chat app. This app provides the user interface for an IM - **iOS state:** Pending ## Information -- [Documentation](https://confluence-public.open-xchange.com/display/COIPublic/OX+Talk+Mobile+App) +- [Documentation](https://github.com/open-xchange/ox-talk/wiki/Developer-Documentation) - The IMAP / SMTP interactions are managed by the [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) ## Requirements From 1296b5c3db501c9d86d2f96b6cec2dc311561906 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 28 Feb 2019 10:33:31 +0100 Subject: [PATCH 06/13] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..ae2e90db --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Occurrence: [always / 5 out of 10 times / rarely] +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**App information (please complete the following information):** + - App version: [e.g. 0.4.0] + - Plugin version: [e.g. 0.4.0] + - Delta Chat Core version: [e.g. 0.40.0] + - Flutter version: [e.g. 1.0] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..0cee7b20 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From f4f41a279849288888b100e26c2b0e5a51160e24 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 28 Feb 2019 10:36:08 +0100 Subject: [PATCH 07/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a420cf90..49aea75e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ OX Talk is a mail based chat app. This app provides the user interface for an IM - The IMAP / SMTP interactions are managed by the [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) ## Requirements -- Flutter 1.0 is used (if problems occur try the [Flutter Dev Channel](https://github.com/flutter/flutter/wiki/Flutter-build-release-channels)) +- The latest Flutter stable version is used (if problems occur try the [Flutter Dev Channel](https://github.com/flutter/flutter/wiki/Flutter-build-release-channels)) - The [delta_chat_core plugin](https://github.com/open-xchange/flutter-deltachat-core) needs to be checked out right beside the OX Talk app (the repositories should be located in the same folder) and please follow the requirements given by that project ## Execution From 27018cc76ffbf21ceee77eb2c255d145e7dfb8b9 Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Thu, 28 Feb 2019 11:20:58 +0100 Subject: [PATCH 08/13] CLEANUP add missing legal headers --- lib/source/widgets/avatar.dart | 42 ++++++++++++++++++++++++ lib/source/widgets/avatar_list_item.dart | 42 ++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/lib/source/widgets/avatar.dart b/lib/source/widgets/avatar.dart index b83d7faa..204f59d2 100644 --- a/lib/source/widgets/avatar.dart +++ b/lib/source/widgets/avatar.dart @@ -1,3 +1,45 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/source/widgets/avatar_list_item.dart b/lib/source/widgets/avatar_list_item.dart index 2934c65f..32a6bd5e 100644 --- a/lib/source/widgets/avatar_list_item.dart +++ b/lib/source/widgets/avatar_list_item.dart @@ -1,3 +1,45 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + import 'package:flutter/material.dart'; import 'package:ox_talk/source/widgets/avatar.dart'; import 'package:ox_talk/source/utils/dimensions.dart'; From eff3efcaae27d857e5a3f9fe11ed00bbaf0daf83 Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Thu, 28 Feb 2019 13:50:26 +0100 Subject: [PATCH 09/13] HOTFIX ui fix for chat subtitle --- lib/source/chat/chat.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/source/chat/chat.dart b/lib/source/chat/chat.dart index cc1316a4..86ec2a01 100644 --- a/lib/source/chat/chat.dart +++ b/lib/source/chat/chat.dart @@ -150,7 +150,14 @@ class _ChatScreenState extends State { size: 18, )) : Container(), - Text(subTitle, style: TextStyle(fontSize: 14)), + Expanded( + child: Text( + subTitle, + style: TextStyle(fontSize: 14), + softWrap: true, + overflow: TextOverflow.ellipsis, + ), + ), ], ), ], From 28315eb556a44ae2adebaf36ad8de6ab750cbfef Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Fri, 1 Mar 2019 13:00:21 +0100 Subject: [PATCH 10/13] OT-94 Handle chat invites --- lib/main.dart | 2 +- lib/source/chat/change_chat_bloc.dart | 90 ++++++++++ lib/source/chat/change_chat_event.dart | 65 +++++++ lib/source/chat/change_chat_state.dart | 90 ++++++++++ lib/source/chat/chat.dart | 8 +- .../{chatlist => chat}/create_chat.dart | 2 +- .../{chatlist => chat}/create_group_chat.dart | 0 lib/source/chatlist/chat_list.dart | 68 ++++++- lib/source/chatlist/chat_list_bloc.dart | 51 ++++-- lib/source/chatlist/chat_list_event.dart | 7 +- .../chatlist/chat_list_invite_item.dart | 167 ++++++++++++++++++ lib/source/chatlist/chat_list_state.dart | 60 +++---- lib/source/contact/contact_change_bloc.dart | 17 +- lib/source/contact/contact_change_event.dart | 8 + lib/source/contact/contact_change_state.dart | 26 +-- lib/source/contact/contact_item.dart | 22 ++- lib/source/contact/contact_list_bloc.dart | 24 ++- lib/source/data/chat_list_repository.dart | 10 +- .../message_attachment_bloc.dart | 4 +- .../message_attachment_event.dart | 0 .../message_attachment_state.dart | 0 lib/source/message/message_change_bloc.dart | 80 +++++++++ lib/source/message/message_change_event.dart | 52 ++++++ lib/source/message/message_change_state.dart | 88 +++++++++ .../{chat => message}/message_item.dart | 24 ++- .../{chat => message}/message_item_bloc.dart | 48 +++-- .../{chat => message}/message_item_event.dart | 0 .../{chat => message}/message_item_state.dart | 57 +++--- .../{chat => message}/messages_bloc.dart | 6 +- .../{chat => message}/messages_event.dart | 0 .../{chat => message}/messages_state.dart | 0 pubspec.yaml | 2 +- 32 files changed, 927 insertions(+), 151 deletions(-) create mode 100644 lib/source/chat/change_chat_bloc.dart create mode 100644 lib/source/chat/change_chat_event.dart create mode 100644 lib/source/chat/change_chat_state.dart rename lib/source/{chatlist => chat}/create_chat.dart (98%) rename lib/source/{chatlist => chat}/create_group_chat.dart (100%) create mode 100644 lib/source/chatlist/chat_list_invite_item.dart rename lib/source/{chat => message}/message_attachment_bloc.dart (95%) rename lib/source/{chat => message}/message_attachment_event.dart (100%) rename lib/source/{chat => message}/message_attachment_state.dart (100%) create mode 100644 lib/source/message/message_change_bloc.dart create mode 100644 lib/source/message/message_change_event.dart create mode 100644 lib/source/message/message_change_state.dart rename lib/source/{chat => message}/message_item.dart (93%) rename lib/source/{chat => message}/message_item_bloc.dart (82%) rename lib/source/{chat => message}/message_item_event.dart (100%) rename lib/source/{chat => message}/message_item_state.dart (84%) rename lib/source/{chat => message}/messages_bloc.dart (95%) rename lib/source/{chat => message}/messages_event.dart (100%) rename lib/source/{chat => message}/messages_state.dart (100%) diff --git a/lib/main.dart b/lib/main.dart index fe37dc37..c6bb8470 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -47,7 +47,7 @@ import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:ox_talk/source/log/bloc_delegate.dart'; -import 'package:ox_talk/source/chatlist/create_chat.dart'; +import 'package:ox_talk/source/chat/create_chat.dart'; import 'package:ox_talk/source/contact/contact_change.dart'; import 'package:ox_talk/source/l10n/localizations.dart'; import 'package:ox_talk/source/login/login.dart'; diff --git a/lib/source/chat/change_chat_bloc.dart b/lib/source/chat/change_chat_bloc.dart new file mode 100644 index 00000000..c6a89b91 --- /dev/null +++ b/lib/source/chat/change_chat_bloc.dart @@ -0,0 +1,90 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:delta_chat_core/delta_chat_core.dart'; +import 'package:ox_talk/source/chat/change_chat_event.dart'; +import 'package:ox_talk/source/chat/change_chat_state.dart'; +import 'package:ox_talk/source/data/chat_repository.dart'; +import 'package:ox_talk/source/data/repository.dart'; +import 'package:ox_talk/source/data/repository_manager.dart'; + +class ChangeChatBloc extends Bloc { + Repository messagesRepository; + + @override + ChangeChatState get initialState => CreateChatStateInitial(); + + @override + Stream mapEventToState(ChangeChatState currentState, ChangeChatEvent event) async* { + if (event is CreateChat) { + yield CreateChatStateLoading(); + try { + messagesRepository = RepositoryManager.get(RepositoryType.chatMessage, event.chatId); + _createChat(contactId: event.contactId, messageId: event.messageId, verified: event.verified, name: event.name); + } catch (error) { + yield CreateChatStateFailure(error: error.toString()); + } + } else if (event is ChatCreated) { + yield CreateChatStateSuccess(chatId: event.chatId); + } + } + + void _createChat({int contactId, int messageId, bool verified, String name}) async { + Context context = Context(); + var chatId; + if (contactId != null) { + chatId = await context.createChatByContactId(contactId); + } else if (messageId != null) { + messagesRepository.remove(messageId); + chatId = await context.createChatByMessageId(messageId); + } else if (verified != null && name != null) { + chatId = await context.createGroupChat(verified, name); + } + Repository chatRepository = ChatRepository(Chat.getCreator()); + chatRepository.putIfAbsent(id: chatId); + dispatch(ChatCreated(chatId: chatId)); + } + +} diff --git a/lib/source/chat/change_chat_event.dart b/lib/source/chat/change_chat_event.dart new file mode 100644 index 00000000..9478d96d --- /dev/null +++ b/lib/source/chat/change_chat_event.dart @@ -0,0 +1,65 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +abstract class ChangeChatEvent {} + +class CreateChat extends ChangeChatEvent { + final int contactId; + final int messageId; + final int chatId; + final bool verified; + final String name; + + CreateChat({ + this.contactId, + this.messageId, + this.chatId, + this.verified, + this.name, + }); +} + +class ChatCreated extends ChangeChatEvent { + final int chatId; + + ChatCreated({this.chatId}); +} diff --git a/lib/source/chat/change_chat_state.dart b/lib/source/chat/change_chat_state.dart new file mode 100644 index 00000000..c7254c1a --- /dev/null +++ b/lib/source/chat/change_chat_state.dart @@ -0,0 +1,90 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +import 'package:meta/meta.dart'; +import 'package:ox_talk/source/base/bloc_base_state.dart'; + +abstract class ChangeChatState extends BaseState { + ChangeChatState({ + @required isLoading, + @required isSuccess, + @required error, + }) : super(isLoading: isLoading, isSuccess: isSuccess, error: error); +} + +class CreateChatStateInitial extends ChangeChatState { + CreateChatStateInitial() + : super( + isLoading: false, + isSuccess: false, + error: '', + ); +} + +class CreateChatStateLoading extends ChangeChatState { + CreateChatStateLoading() + : super( + isLoading: true, + isSuccess: false, + error: '', + ); +} + +class CreateChatStateSuccess extends ChangeChatState { + final int chatId; + + CreateChatStateSuccess({@required this.chatId}) + : super( + isLoading: false, + isSuccess: true, + error: '', + ); +} + +class CreateChatStateFailure extends ChangeChatState { + CreateChatStateFailure({@required error}) + : super( + isLoading: false, + isSuccess: false, + error: error, + ); +} diff --git a/lib/source/chat/chat.dart b/lib/source/chat/chat.dart index 86ec2a01..690d26da 100644 --- a/lib/source/chat/chat.dart +++ b/lib/source/chat/chat.dart @@ -46,12 +46,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:ox_talk/source/chat/chat_bloc.dart'; import 'package:ox_talk/source/chat/chat_event.dart'; import 'package:ox_talk/source/chat/chat_state.dart'; -import 'package:ox_talk/source/chat/messages_bloc.dart'; -import 'package:ox_talk/source/chat/messages_event.dart'; -import 'package:ox_talk/source/chat/messages_state.dart'; +import 'package:ox_talk/source/message/messages_bloc.dart'; +import 'package:ox_talk/source/message/messages_event.dart'; +import 'package:ox_talk/source/message/messages_state.dart'; import 'package:ox_talk/source/widgets/avatar.dart'; -import 'message_item.dart'; +import 'package:ox_talk/source/message/message_item.dart'; class ChatScreen extends StatefulWidget { final int _chatId; diff --git a/lib/source/chatlist/create_chat.dart b/lib/source/chat/create_chat.dart similarity index 98% rename from lib/source/chatlist/create_chat.dart rename to lib/source/chat/create_chat.dart index b2f632c4..1ebc6c10 100644 --- a/lib/source/chatlist/create_chat.dart +++ b/lib/source/chat/create_chat.dart @@ -42,7 +42,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:ox_talk/source/chatlist/create_group_chat.dart'; +import 'package:ox_talk/source/chat/create_group_chat.dart'; import 'package:ox_talk/source/contact/contact_change.dart'; import 'package:ox_talk/source/contact/contact_item.dart'; import 'package:ox_talk/source/contact/contact_list_bloc.dart'; diff --git a/lib/source/chatlist/create_group_chat.dart b/lib/source/chat/create_group_chat.dart similarity index 100% rename from lib/source/chatlist/create_group_chat.dart rename to lib/source/chat/create_group_chat.dart diff --git a/lib/source/chatlist/chat_list.dart b/lib/source/chatlist/chat_list.dart index b627940e..6505f3bb 100644 --- a/lib/source/chatlist/chat_list.dart +++ b/lib/source/chatlist/chat_list.dart @@ -46,6 +46,7 @@ import 'package:ox_talk/main.dart'; import 'package:ox_talk/source/base/base_root_child.dart'; import 'package:ox_talk/source/chatlist/chat_list_bloc.dart'; import 'package:ox_talk/source/chatlist/chat_list_event.dart'; +import 'package:ox_talk/source/chatlist/chat_list_invite_item.dart'; import 'package:ox_talk/source/chatlist/chat_list_item.dart'; import 'package:ox_talk/source/chatlist/chat_list_state.dart'; import 'package:ox_talk/source/l10n/localizations.dart'; @@ -105,7 +106,7 @@ class _ChatListState extends State { bloc: _chatListBloc, builder: (context, state) { if (state is ChatListStateSuccess) { - return buildListViewItems(state.chatIds, state.chatLastUpdateValues); + return buildListViewItems(state.chatIds, state.chatLastUpdateValues, state.messageIds, state.messagesLastUpdateValues); } else if (state is! ChatListStateFailure) { return Center( child: CircularProgressIndicator(), @@ -117,15 +118,70 @@ class _ChatListState extends State { ); } - Widget buildListViewItems(List chatIds, List chatLastUpdateValues) { + Widget buildListViewItems(List chatIds, List chatLastUpdateValues, List messageIds, List messagesLastUpdateValues) { return ListView.builder( padding: EdgeInsets.all(listItemPadding), - itemCount: chatIds.length, + itemCount: messageIds != null ? chatIds.length + messageIds.length : chatIds.length, itemBuilder: (BuildContext context, int index) { - var chatId = chatIds[index]; - var key = "$chatId-${chatLastUpdateValues[index]}"; - return ChatListItem(chatId, key); + if (messageIds != null) { + if (index < messageIds.length) { + var messageId = messageIds[index]; + var key = "$messageId-${messagesLastUpdateValues[index]}"; + return buildInviteItem(index, messageId, key); + } else { + return buildChatListItem(messageIds, index, chatIds, chatLastUpdateValues); + } + } else { + var chatId = chatIds[index]; + var key = "$chatId-${chatLastUpdateValues[index]}"; + return ChatListItem(chatId, key); + } }, ); } + + Widget buildInviteItem(int index, int messageId, String key) { + if (index == 0) { + return Column( + children: [ + createHeader(invite: true), + ChatListInviteItem(1, messageId, key), + ], + ); + } else { + return ChatListInviteItem(1, messageId, key); + } + } + + Widget createHeader({bool invite = false, bool chats = false}) { + if (invite) { + return Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Text("Open requests"), + ); + } else if (chats) { + return Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Text("Active chats"), + ); + } else { + return Container(); + } + } + + Widget buildChatListItem(List messageIds, int index, List chatIds, List chatLastUpdateValues) { + var newIndex = messageIds != null ? index - messageIds.length : index; + var chatId = chatIds[newIndex]; + var key = "$chatId-${chatLastUpdateValues[newIndex]}"; + if (index == messageIds.length && index != 0) { + return Column( + children: [ + createHeader(chats: true), + ChatListItem(chatId, key), + ], + ); + } else { + return ChatListItem(chatId, key); + } + } } diff --git a/lib/source/chatlist/chat_list_bloc.dart b/lib/source/chatlist/chat_list_bloc.dart index 3d4b316e..7f10dd10 100644 --- a/lib/source/chatlist/chat_list_bloc.dart +++ b/lib/source/chatlist/chat_list_bloc.dart @@ -44,20 +44,26 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:delta_chat_core/delta_chat_core.dart'; +import 'package:ox_talk/source/message/messages_bloc.dart'; +import 'package:ox_talk/source/message/messages_event.dart'; +import 'package:ox_talk/source/message/messages_state.dart'; import 'package:ox_talk/source/chatlist/chat_list_event.dart'; import 'package:ox_talk/source/chatlist/chat_list_state.dart'; import 'package:ox_talk/source/data/repository.dart'; import 'package:ox_talk/source/data/repository_manager.dart'; +import 'package:rxdart/rxdart.dart'; + class ChatListBloc extends Bloc { final Repository chatListRepository = RepositoryManager.get(RepositoryType.chatList); final Repository chatRepository = RepositoryManager.get(RepositoryType.chat); StreamSubscription streamSubscription; + MessagesBloc _messagesBloc = MessagesBloc(); @override ChatListState get initialState => ChatListStateInitial(); @override - Stream mapEventToState(ChatListState currentState, ChatListEvent event) async*{ + Stream mapEventToState(ChatListState currentState, ChatListEvent event) async* { if (event is RequestChatList) { yield ChatListStateLoading(); try { @@ -66,36 +72,49 @@ class ChatListBloc extends Bloc { } catch (error) { yield ChatListStateFailure(error: error.toString()); } - }else if(event is ChatListModified){ - yield ChatListStateSuccess(chatIds: chatRepository.getAllIds(), chatLastUpdateValues: chatRepository.getAllLastUpdateValues()); + } else if (event is ChatListModified) { + yield ChatListStateSuccess( + chatIds: chatRepository.getAllIds(), + chatLastUpdateValues: chatRepository.getAllLastUpdateValues(), + messageIds: event.messageIds, + messagesLastUpdateValues: event.messagesLastUpdateValues); } } @override void dispose() { super.dispose(); - chatListRepository.removeListener(hashCode, Event.chatModified); + chatListRepository.removeListener(hashCode, Event.msgsChanged); + chatListRepository.removeListener(hashCode, Event.contactsChanged); streamSubscription.cancel(); } - void setupChatList() async{ + void setupChatList() async { ChatList chatList = ChatList(); int chatCount = await chatList.getChatCnt(); List chatIds = List(); - - if (chatCount > 0) { - for (int i = 0; i < chatCount; i++) { - int chatId = await chatList.getChat(i); - chatIds.add(chatId); - } + for (int i = 0; i < chatCount; i++) { + int chatId = await chatList.getChat(i); + chatIds.add(chatId); } - chatRepository.putIfAbsent(ids: chatIds); - dispatch(ChatListModified()); + + _messagesBloc.dispatch(RequestMessages(1)); + final userStatesObservable = new Observable(_messagesBloc.state); + userStatesObservable.listen((state) => _handleMessagesStateChange(state)); + } + + _handleMessagesStateChange(MessagesState state) { + if (state is MessagesStateSuccess) { + dispatch(ChatListModified(state.messageIds, state.messageLastUpdateValues)); + } } void setupChatListListener() { - chatListRepository.addListener(hashCode, Event.chatModified); - streamSubscription = chatListRepository.observable.listen((event) => dispatch(ChatListModified())); + if (streamSubscription == null) { + chatListRepository.addListener(hashCode, Event.msgsChanged); + chatListRepository.addListener(hashCode, Event.contactsChanged); + streamSubscription = chatListRepository.observable.listen((event) => dispatch(RequestChatList())); + } } -} \ No newline at end of file +} diff --git a/lib/source/chatlist/chat_list_event.dart b/lib/source/chatlist/chat_list_event.dart index 5feae1c1..6956775c 100644 --- a/lib/source/chatlist/chat_list_event.dart +++ b/lib/source/chatlist/chat_list_event.dart @@ -44,4 +44,9 @@ abstract class ChatListEvent {} class RequestChatList extends ChatListEvent {} -class ChatListModified extends ChatListEvent {} \ No newline at end of file +class ChatListModified extends ChatListEvent { + final List messageIds; + final List messagesLastUpdateValues; + + ChatListModified(this.messageIds, this.messagesLastUpdateValues); +} diff --git a/lib/source/chatlist/chat_list_invite_item.dart b/lib/source/chatlist/chat_list_invite_item.dart new file mode 100644 index 00000000..4f50a002 --- /dev/null +++ b/lib/source/chatlist/chat_list_invite_item.dart @@ -0,0 +1,167 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:ox_talk/source/chat/change_chat_bloc.dart'; +import 'package:ox_talk/source/chat/change_chat_event.dart'; +import 'package:ox_talk/source/chat/change_chat_state.dart'; +import 'package:ox_talk/source/chat/chat.dart'; +import 'package:ox_talk/source/contact/contact_change_bloc.dart'; +import 'package:ox_talk/source/contact/contact_change_event.dart'; +import 'package:ox_talk/source/message/message_change_bloc.dart'; +import 'package:ox_talk/source/message/message_change_event.dart'; +import 'package:ox_talk/source/message/message_change_state.dart'; +import 'package:ox_talk/source/message/message_item_bloc.dart'; +import 'package:ox_talk/source/message/message_item_event.dart'; +import 'package:ox_talk/source/message/message_item_state.dart'; +import 'package:ox_talk/source/widgets/avatar_list_item.dart'; +import 'package:rxdart/rxdart.dart'; + +class ChatListInviteItem extends StatefulWidget { + final int _chatId; + final int _messageId; + + ChatListInviteItem(this._chatId, this._messageId, key) : super(key: Key(key)); + + @override + _ChatListInviteItemState createState() => _ChatListInviteItemState(); +} + +class _ChatListInviteItemState extends State { + MessageItemBloc _messageItemBloc = MessageItemBloc(); + int _contactId; + + @override + void initState() { + super.initState(); + _messageItemBloc.dispatch(RequestMessage(widget._chatId, widget._messageId, false)); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + bloc: _messageItemBloc, + builder: (context, state) { + String name; + String subTitle; + Color color; + if (state is MessageItemStateSuccess) { + var contactWrapper = state.contactWrapper; + _contactId = contactWrapper.contactId; + name = contactWrapper.contactAddress; + subTitle = state.messageText; + color = Colors.blue; + } else { + name = ""; + subTitle = ""; + } + return AvatarListItem( + title: name, + subTitle: subTitle, + color: color, + onTap: inviteItemTapped, + ); + }, + ); + } + + inviteItemTapped(String name, String message) { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("Start a chat with $name?"), + content: new Text(message), + actions: [ + new FlatButton( + child: new Text("Cancel"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + new FlatButton( + child: new Text("Block"), + onPressed: () { + blockUser(); + Navigator.of(context).pop(); + }, + ), + new FlatButton( + child: new Text("Yes"), + onPressed: () { + createChat(); + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + } + + void createChat() async { + ChangeChatBloc createChatBloc = ChangeChatBloc(); + final changeChatStatesObservable = new Observable(createChatBloc.state); + changeChatStatesObservable.listen((state) => _handleChangeChatStateChange(state)); + createChatBloc.dispatch(CreateChat(messageId: widget._messageId, chatId: widget._chatId)); + } + + _handleChangeChatStateChange(ChangeChatState state) { + if (state is CreateChatStateSuccess) { + Navigator.push(context, MaterialPageRoute(builder: (context) => ChatScreen(state.chatId))); + } + } + + void blockUser() { + MessageChangeBloc messageChangeBloc = MessageChangeBloc(); + messageChangeBloc.dispatch(DeleteMessage(widget._chatId, widget._messageId)); + final messageChangeStatesObservable = new Observable(messageChangeBloc.state); + messageChangeStatesObservable.listen((state) => _handleMessageChangeStateChange(state)); + } + + _handleMessageChangeStateChange(MessageChangeState state) { + if (state is MessageChangeStateSuccess) { + ContactChangeBloc contactChangeBloc = ContactChangeBloc(); + contactChangeBloc.dispatch(BlockContact(_contactId)); + } + } +} diff --git a/lib/source/chatlist/chat_list_state.dart b/lib/source/chatlist/chat_list_state.dart index 7c6aeb48..7b9817f3 100644 --- a/lib/source/chatlist/chat_list_state.dart +++ b/lib/source/chatlist/chat_list_state.dart @@ -44,58 +44,54 @@ import 'package:flutter/material.dart'; import 'package:ox_talk/source/base/bloc_base_state.dart'; abstract class ChatListState extends BaseState { - final List chatIds; - final List chatLastUpdateValues; - ChatListState({ @required isLoading, @required isSuccess, @required error, - @required this.chatIds, - @required this.chatLastUpdateValues, }) : super(isLoading: isLoading, isSuccess: isSuccess, error: error); } class ChatListStateInitial extends ChatListState { ChatListStateInitial() : super( - isLoading: false, - isSuccess: false, - error: '', - chatIds: null, - chatLastUpdateValues: null, - ); + isLoading: false, + isSuccess: false, + error: '', + ); } class ChatListStateLoading extends ChatListState { ChatListStateLoading() : super( - isLoading: true, - isSuccess: false, - error: '', - chatIds: List(), - chatLastUpdateValues: List(), - ); + isLoading: true, + isSuccess: false, + error: '', + ); } class ChatListStateSuccess extends ChatListState { - ChatListStateSuccess({@required List chatIds, @required List chatLastUpdateValues}) - : super( - isLoading: false, - isSuccess: true, - error: '', - chatIds: chatIds, - chatLastUpdateValues: chatLastUpdateValues, - ); + final List chatIds; + final List chatLastUpdateValues; + final List messageIds; + final List messagesLastUpdateValues; + + ChatListStateSuccess({ + @required this.chatIds, + @required this.chatLastUpdateValues, + @required this.messageIds, + @required this.messagesLastUpdateValues, + }) : super( + isLoading: false, + isSuccess: true, + error: '', + ); } class ChatListStateFailure extends ChatListState { ChatListStateFailure({@required error}) : super( - isLoading: false, - isSuccess: false, - error: error, - chatIds: null, - chatLastUpdateValues: null, - ); -} \ No newline at end of file + isLoading: false, + isSuccess: false, + error: error, + ); +} diff --git a/lib/source/contact/contact_change_bloc.dart b/lib/source/contact/contact_change_bloc.dart index 9785ff24..a1b4e249 100644 --- a/lib/source/contact/contact_change_bloc.dart +++ b/lib/source/contact/contact_change_bloc.dart @@ -67,15 +67,19 @@ class ContactChangeBloc extends Bloc { yield ContactChangeStateFailure(error: error.toString()); } } else if (event is ContactAdded) { - yield ContactChangeStateSuccess(add: true, delete: false, id: event.id); + yield ContactChangeStateSuccess(add: true, delete: false, blocked: false, id: event.id); } else if (event is ContactEdited) { - yield ContactChangeStateSuccess(add: false, delete: false, id: null); + yield ContactChangeStateSuccess(add: false, delete: false, blocked: false, id: null); } else if (event is DeleteContact) { _deleteContact(event.id); } else if (event is ContactDeleted) { - yield ContactChangeStateSuccess(add: false, delete: true, id: null); + yield ContactChangeStateSuccess(add: false, delete: true, blocked: false, id: null); } else if (event is ContactDeleteFailed) { yield ContactChangeStateFailure(error: contactDelete); + } else if (event is BlockContact) { + _blockContact(event.id); + } else if (event is ContactBlocked) { + yield ContactChangeStateSuccess(add: false, delete: false, blocked: true, id: null); } } @@ -101,4 +105,11 @@ class ContactChangeBloc extends Bloc { dispatch(ContactDeleteFailed()); } } + + void _blockContact(int id) async { + contactRepository.remove(id); + Context context = Context(); + await context.blockContact(id); + dispatch(ContactBlocked()); + } } diff --git a/lib/source/contact/contact_change_event.dart b/lib/source/contact/contact_change_event.dart index cd3497d5..17cd9578 100644 --- a/lib/source/contact/contact_change_event.dart +++ b/lib/source/contact/contact_change_event.dart @@ -69,3 +69,11 @@ class ContactEdited extends ContactChangeEvent {} class ContactDeleted extends ContactChangeEvent {} class ContactDeleteFailed extends ContactChangeEvent {} + +class BlockContact extends ContactChangeEvent { + final int id; + + BlockContact(this.id); +} + +class ContactBlocked extends ContactChangeEvent {} diff --git a/lib/source/contact/contact_change_state.dart b/lib/source/contact/contact_change_state.dart index 28de2535..9a3c7a35 100644 --- a/lib/source/contact/contact_change_state.dart +++ b/lib/source/contact/contact_change_state.dart @@ -46,16 +46,18 @@ import 'package:ox_talk/source/base/bloc_base_state.dart'; abstract class ContactChangeState extends BaseState { final bool add; final bool delete; + final bool blocked; final int id; - ContactChangeState({ - @required isLoading, - @required isSuccess, - @required error, - @required this.add, - @required this.delete, - @required this.id - }) : super(isLoading: isLoading, isSuccess: isSuccess, error: error); + ContactChangeState( + {@required isLoading, + @required isSuccess, + @required error, + @required this.add, + @required this.delete, + @required this.blocked, + @required this.id}) + : super(isLoading: isLoading, isSuccess: isSuccess, error: error); } class ContactChangeStateInitial extends ContactChangeState { @@ -66,6 +68,7 @@ class ContactChangeStateInitial extends ContactChangeState { error: '', add: null, delete: null, + blocked: null, id: null, ); } @@ -78,18 +81,20 @@ class ContactChangeStateLoading extends ContactChangeState { error: '', add: null, delete: null, + blocked: null, id: null, ); } class ContactChangeStateSuccess extends ContactChangeState { - ContactChangeStateSuccess({@required bool add, @required bool delete, @required int id}) + ContactChangeStateSuccess({@required bool add, @required bool delete, @required bool blocked, @required int id}) : super( isLoading: false, isSuccess: true, error: '', add: add, delete: delete, + blocked: blocked, id: id, ); } @@ -102,6 +107,7 @@ class ContactChangeStateFailure extends ContactChangeState { error: error, add: null, delete: null, + blocked: null, id: null, ); -} \ No newline at end of file +} diff --git a/lib/source/contact/contact_item.dart b/lib/source/contact/contact_item.dart index e79228bf..abb10911 100644 --- a/lib/source/contact/contact_item.dart +++ b/lib/source/contact/contact_item.dart @@ -40,17 +40,18 @@ * for more details. */ -import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:ox_talk/source/chat/chat.dart'; +import 'package:ox_talk/source/chat/change_chat_bloc.dart'; +import 'package:ox_talk/source/chat/change_chat_event.dart'; +import 'package:ox_talk/source/chat/change_chat_state.dart'; import 'package:ox_talk/source/contact/contact_change.dart'; import 'package:ox_talk/source/contact/contact_item_bloc.dart'; import 'package:ox_talk/source/contact/contact_item_event.dart'; import 'package:ox_talk/source/contact/contact_item_state.dart'; -import 'package:ox_talk/source/data/chat_repository.dart'; -import 'package:ox_talk/source/data/repository.dart'; import 'package:ox_talk/source/widgets/avatar_list_item.dart'; +import 'package:rxdart/rxdart.dart'; class ContactItem extends StatefulWidget { final int _contactId; @@ -64,7 +65,6 @@ class ContactItem extends StatefulWidget { class _ContactItemState extends State { ContactItemBloc _contactBloc = ContactItemBloc(); - Repository chatRepository = ChatRepository(Chat.getCreator()); @override void initState() { @@ -136,9 +136,15 @@ class _ContactItemState extends State { } void createChat() async { - Context coreContext = Context(); - var chatId = await coreContext.createChatByContactId(widget._contactId); - chatRepository.putIfAbsent(id: chatId); - Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ChatScreen(chatId))); + ChangeChatBloc createChatBloc = ChangeChatBloc(); + final createChatStatesObservable = new Observable(createChatBloc.state); + createChatStatesObservable.listen((state) => _handleCreateChatStateChange(state)); + createChatBloc.dispatch(CreateChat(contactId: widget._contactId)); + } + + _handleCreateChatStateChange(ChangeChatState state) { + if (state is CreateChatStateSuccess) { + Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => ChatScreen(state.chatId))); + } } } diff --git a/lib/source/contact/contact_list_bloc.dart b/lib/source/contact/contact_list_bloc.dart index 881f5b84..0750295a 100644 --- a/lib/source/contact/contact_list_bloc.dart +++ b/lib/source/contact/contact_list_bloc.dart @@ -52,6 +52,7 @@ import 'package:ox_talk/source/data/repository_manager.dart'; class ContactListBloc extends Bloc { final Repository contactRepository = RepositoryManager.get(RepositoryType.contact); StreamSubscription streamSubscription; + List validContactIds = List(); @override ContactListState get initialState => ContactListStateInitial(); @@ -67,7 +68,16 @@ class ContactListBloc extends Bloc { yield ContactListStateFailure(error: error.toString()); } } else if (event is ContactsChanged) { - yield ContactListStateSuccess(contactIds: contactRepository.getAllIds(), contactLastUpdateValues: contactRepository.getAllLastUpdateValues()); + List resultValidContactIds = List(); + List resultValidContactLastUpdateValues = List(); + for (int index = 0; index < contactRepository.getAllIds().length; index++) { + var contact = contactRepository.get(index); + if (validContactIds.contains(contact.getId())) { + resultValidContactIds.add(contact.getId()); + resultValidContactLastUpdateValues.add(contact.lastUpdate); + } + } + yield ContactListStateSuccess(contactIds: resultValidContactIds, contactLastUpdateValues: resultValidContactLastUpdateValues); } } @@ -80,14 +90,18 @@ class ContactListBloc extends Bloc { void setupContactListener() async { contactRepository.addListener(hashCode, Event.contactsChanged); - streamSubscription = contactRepository.observable.listen((event) => dispatch(ContactsChanged())); + streamSubscription = contactRepository.observable.listen((event) => dispatchContactsChanged()); + } + + void dispatchContactsChanged() { + validContactIds = contactRepository.getAllIds(); + dispatch(ContactsChanged()); } void setupContacts() async { Context _context = Context(); - List contactIds = List.from(await _context.getContacts(2, null)); - contactRepository.putIfAbsent(ids: contactIds); + validContactIds = List.from(await _context.getContacts(2, null)); + contactRepository.putIfAbsent(ids: validContactIds); dispatch(ContactsChanged()); } - } diff --git a/lib/source/data/chat_list_repository.dart b/lib/source/data/chat_list_repository.dart index fc7c8abe..df1b3efd 100644 --- a/lib/source/data/chat_list_repository.dart +++ b/lib/source/data/chat_list_repository.dart @@ -46,16 +46,16 @@ import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:ox_talk/source/data/repository.dart'; class ChatListRepository extends Repository { - ChatListRepository(RepositoryItemCreator creator) : super(creator); @override - success(Event event) async{ - if (event.eventId == Event.chatModified) { + success(Event event) async { + if (event.eventId == Event.msgsChanged) { await setupChatListAfterUpdate(); } super.success(event); } + Future setupChatListAfterUpdate() async { ChatList chatList = ChatList(); int chatCount = await chatList.getChatCnt(); @@ -73,6 +73,4 @@ class ChatListRepository extends Repository { error(error) { super.error(error); } - - -} \ No newline at end of file +} diff --git a/lib/source/chat/message_attachment_bloc.dart b/lib/source/message/message_attachment_bloc.dart similarity index 95% rename from lib/source/chat/message_attachment_bloc.dart rename to lib/source/message/message_attachment_bloc.dart index 7bcdd704..ba949ff5 100644 --- a/lib/source/chat/message_attachment_bloc.dart +++ b/lib/source/message/message_attachment_bloc.dart @@ -45,8 +45,8 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:open_file/open_file.dart'; -import 'package:ox_talk/source/chat/message_attachment_event.dart'; -import 'package:ox_talk/source/chat/message_attachment_state.dart'; +import 'package:ox_talk/source/message/message_attachment_event.dart'; +import 'package:ox_talk/source/message/message_attachment_state.dart'; import 'package:ox_talk/source/data/repository.dart'; import 'package:ox_talk/source/data/repository_manager.dart'; diff --git a/lib/source/chat/message_attachment_event.dart b/lib/source/message/message_attachment_event.dart similarity index 100% rename from lib/source/chat/message_attachment_event.dart rename to lib/source/message/message_attachment_event.dart diff --git a/lib/source/chat/message_attachment_state.dart b/lib/source/message/message_attachment_state.dart similarity index 100% rename from lib/source/chat/message_attachment_state.dart rename to lib/source/message/message_attachment_state.dart diff --git a/lib/source/message/message_change_bloc.dart b/lib/source/message/message_change_bloc.dart new file mode 100644 index 00000000..f0a311e2 --- /dev/null +++ b/lib/source/message/message_change_bloc.dart @@ -0,0 +1,80 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:delta_chat_core/delta_chat_core.dart'; +import 'package:ox_talk/source/data/repository.dart'; +import 'package:ox_talk/source/data/repository_manager.dart'; +import 'package:ox_talk/source/message/message_change_event.dart'; +import 'package:ox_talk/source/message/message_change_state.dart'; + +class MessageChangeBloc extends Bloc { + Repository messagesRepository; + + @override + MessageChangeState get initialState => MessageChangeStateInitial(); + + @override + Stream mapEventToState(MessageChangeState currentState, MessageChangeEvent event) async* { + if (event is DeleteMessage) { + yield MessageChangeStateLoading(); + try { + messagesRepository = RepositoryManager.get(RepositoryType.chatMessage, event.chatId); + _deleteMessage(event.messageId, false); + } catch (error) { + yield MessageChangeStateFailure(error: error.toString()); + } + } else if (event is MessageDeleted) { + yield MessageChangeStateSuccess(); + } + } + + void _deleteMessage(int messageId, bool deleteInCore) async { + messagesRepository.remove(messageId); + if (deleteInCore) { + //TODO Delete messages from core + } + dispatch(MessageDeleted()); + } +} diff --git a/lib/source/message/message_change_event.dart b/lib/source/message/message_change_event.dart new file mode 100644 index 00000000..ae8548e8 --- /dev/null +++ b/lib/source/message/message_change_event.dart @@ -0,0 +1,52 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +abstract class MessageChangeEvent {} + +class DeleteMessage extends MessageChangeEvent { + final int chatId; + final int messageId; + + DeleteMessage(this.chatId, this.messageId); +} + +class MessageDeleted extends MessageChangeEvent {} diff --git a/lib/source/message/message_change_state.dart b/lib/source/message/message_change_state.dart new file mode 100644 index 00000000..fb134004 --- /dev/null +++ b/lib/source/message/message_change_state.dart @@ -0,0 +1,88 @@ +/* + * OPEN-XCHANGE legal information + * + * All intellectual property rights in the Software are protected by + * international copyright laws. + * + * + * In some countries OX, OX Open-Xchange and open xchange + * as well as the corresponding Logos OX Open-Xchange and OX are registered + * trademarks of the OX Software GmbH group of companies. + * The use of the Logos is not covered by the Mozilla Public License 2.0 (MPL 2.0). + * Instead, you are allowed to use these Logos according to the terms and + * conditions of the Creative Commons License, Version 2.5, Attribution, + * Non-commercial, ShareAlike, and the interpretation of the term + * Non-commercial applicable to the aforementioned license is published + * on the web site https://www.open-xchange.com/terms-and-conditions/. + * + * Please make sure that third-party modules and libraries are used + * according to their respective licenses. + * + * Any modifications to this package must retain all copyright notices + * of the original copyright holder(s) for the original code used. + * + * After any such modifications, the original and derivative code shall remain + * under the copyright of the copyright holder(s) and/or original author(s) as stated here: + * https://www.open-xchange.com/legal/. The contributing author shall be + * given Attribution for the derivative code and a license granting use. + * + * Copyright (C) 2016-2020 OX Software GmbH + * Mail: info@open-xchange.com + * + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * 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 Mozilla Public License 2.0 + * for more details. + */ + +import 'package:meta/meta.dart'; +import 'package:ox_talk/source/base/bloc_base_state.dart'; + +abstract class MessageChangeState extends BaseState { + MessageChangeState({ + @required isLoading, + @required isSuccess, + @required error, + }) : super(isLoading: isLoading, isSuccess: isSuccess, error: error); +} + +class MessageChangeStateInitial extends MessageChangeState { + MessageChangeStateInitial() + : super( + isLoading: false, + isSuccess: false, + error: '', + ); +} + +class MessageChangeStateLoading extends MessageChangeState { + MessageChangeStateLoading() + : super( + isLoading: true, + isSuccess: false, + error: '', + ); +} + +class MessageChangeStateSuccess extends MessageChangeState { + MessageChangeStateSuccess() + : super( + isLoading: false, + isSuccess: true, + error: '', + ); +} + +class MessageChangeStateFailure extends MessageChangeState { + MessageChangeStateFailure({@required error}) + : super( + isLoading: false, + isSuccess: false, + error: error, + ); +} diff --git a/lib/source/chat/message_item.dart b/lib/source/message/message_item.dart similarity index 93% rename from lib/source/chat/message_item.dart rename to lib/source/message/message_item.dart index 7f35a545..85bc7c0d 100644 --- a/lib/source/chat/message_item.dart +++ b/lib/source/message/message_item.dart @@ -45,13 +45,13 @@ import 'dart:io'; import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:ox_talk/source/chat/message_attachment_bloc.dart'; -import 'package:ox_talk/source/chat/message_attachment_event.dart'; -import 'package:ox_talk/source/chat/message_item_bloc.dart'; -import 'package:ox_talk/source/chat/message_item_event.dart'; -import 'package:ox_talk/source/chat/message_item_state.dart'; -import 'package:ox_talk/source/widgets/avatar.dart'; +import 'package:ox_talk/source/message/message_attachment_bloc.dart'; +import 'package:ox_talk/source/message/message_attachment_event.dart'; +import 'package:ox_talk/source/message/message_item_bloc.dart'; +import 'package:ox_talk/source/message/message_item_event.dart'; +import 'package:ox_talk/source/message/message_item_state.dart'; import 'package:ox_talk/source/utils/conversion.dart'; +import 'package:ox_talk/source/widgets/avatar.dart'; class ChatMessageItem extends StatefulWidget { final int _chatId; @@ -198,10 +198,16 @@ class _ChatMessageItemState extends State with TickerProviderSt } Widget buildReceivedMessage(bool isGroupChat, MessageItemStateSuccess state) { - String name = state.contactName; - String email = state.contactAddress; + ContactWrapper contactWrapper = state.contactWrapper; + String name; + String email; + Color color; + if (contactWrapper != null) { + name = contactWrapper.contactName; + email = contactWrapper.contactAddress; + color = contactWrapper.contactColor; + } String text = state.messageText; - Color color = state.contactColor; String time = state.messageTimestamp; bool hasFile = state.hasFile; return FractionallySizedBox( diff --git a/lib/source/chat/message_item_bloc.dart b/lib/source/message/message_item_bloc.dart similarity index 82% rename from lib/source/chat/message_item_bloc.dart rename to lib/source/message/message_item_bloc.dart index 38a1310e..695e4fa5 100644 --- a/lib/source/chat/message_item_bloc.dart +++ b/lib/source/message/message_item_bloc.dart @@ -45,19 +45,19 @@ import 'dart:ui'; import 'package:bloc/bloc.dart'; import 'package:delta_chat_core/delta_chat_core.dart'; -import 'package:ox_talk/source/chat/message_item_event.dart'; -import 'package:ox_talk/source/chat/message_item_state.dart'; +import 'package:ox_talk/source/message/message_item_event.dart'; +import 'package:ox_talk/source/message/message_item_state.dart'; import 'package:ox_talk/source/data/repository.dart'; import 'package:ox_talk/source/data/repository_manager.dart'; -import 'package:ox_talk/source/utils/date.dart'; import 'package:ox_talk/source/utils/colors.dart'; +import 'package:ox_talk/source/utils/date.dart'; class MessageItemBloc extends Bloc { final Repository _contactRepository = RepositoryManager.get(RepositoryType.contact); Repository _messagesRepository; int _messageId; int _contactId; - bool _isGroupChat; + bool _addContact; @override MessageItemState get initialState => MessageItemStateInitial(); @@ -67,10 +67,11 @@ class MessageItemBloc extends Bloc { if (event is RequestMessage) { yield MessageItemStateLoading(); try { - _messagesRepository = RepositoryManager.get(RepositoryType.chatMessage, event.chatId); + var chatId = event.chatId; + _messagesRepository = RepositoryManager.get(RepositoryType.chatMessage, chatId); _messageId = event.messageId; - _isGroupChat = event.isGroupChat; - if (_isGroupChat) { + _addContact = event.isGroupChat || chatId == ChatList.specialInvite; + if (_addContact) { _setupContact(); } _setupMessage(); @@ -84,9 +85,9 @@ class MessageItemBloc extends Bloc { String text = await message.getText(); bool hasFile = await message.hasFile(); String timestamp = getTimeFromTimestamp(await message.getTimestamp()); - AttachmentWrapper attachment; + AttachmentWrapper attachmentWrapper; if (hasFile) { - attachment = AttachmentWrapper( + attachmentWrapper = AttachmentWrapper( filename: await message.getFileName(), path: await message.getFile(), mimeType: await message.getFileMime(), @@ -94,27 +95,36 @@ class MessageItemBloc extends Bloc { type: await message.getType(), ); } - if (_isGroupChat) { + + ContactWrapper contactWrapper; + if (_addContact) { Contact contact = _getContact(); + int contactId = contact.getId(); String contactName = await contact.getName(); String contactAddress = await contact.getAddress(); Color contactColor = rgbColorFromInt(await contact.getColor()); + contactWrapper = ContactWrapper( + contactId: contactId, + contactName: contactName, + contactAddress: contactAddress, + contactColor: contactColor, + ); yield MessageItemStateSuccess( - attachmentWrapper: attachment, - contactName: contactName, - contactAddress: contactAddress, - contactColor: contactColor, - messageIsOutgoing: isOutgoing, - messageText: text, - hasFile: hasFile, - messageTimestamp: timestamp); + messageIsOutgoing: isOutgoing, + messageText: text, + hasFile: hasFile, + messageTimestamp: timestamp, + attachmentWrapper: attachmentWrapper, + contactWrapper: contactWrapper, + ); } else { yield MessageItemStateSuccess( - attachmentWrapper: attachment, messageIsOutgoing: isOutgoing, messageText: text, hasFile: hasFile, messageTimestamp: timestamp, + attachmentWrapper: attachmentWrapper, + contactWrapper: contactWrapper, ); } } diff --git a/lib/source/chat/message_item_event.dart b/lib/source/message/message_item_event.dart similarity index 100% rename from lib/source/chat/message_item_event.dart rename to lib/source/message/message_item_event.dart diff --git a/lib/source/chat/message_item_state.dart b/lib/source/message/message_item_state.dart similarity index 84% rename from lib/source/chat/message_item_state.dart rename to lib/source/message/message_item_state.dart index d28d21f5..8e325fce 100644 --- a/lib/source/chat/message_item_state.dart +++ b/lib/source/message/message_item_state.dart @@ -56,29 +56,27 @@ abstract class MessageItemState extends BaseState { class MessageItemStateInitial extends MessageItemState { MessageItemStateInitial() : super( - isLoading: false, - isSuccess: false, - error: '', - ); + isLoading: false, + isSuccess: false, + error: '', + ); } class MessageItemStateLoading extends MessageItemState { MessageItemStateLoading() : super( - isLoading: true, - isSuccess: false, - error: '', - ); + isLoading: true, + isSuccess: false, + error: '', + ); } class MessageItemStateSuccess extends MessageItemState { - final String contactName; - final String contactAddress; - final Color contactColor; final String messageText; final String messageTimestamp; final bool messageIsOutgoing; final bool hasFile; + final ContactWrapper contactWrapper; final AttachmentWrapper attachmentWrapper; MessageItemStateSuccess({ @@ -87,23 +85,35 @@ class MessageItemStateSuccess extends MessageItemState { @required this.messageTimestamp, @required this.hasFile, @required this.attachmentWrapper, - this.contactName, - this.contactAddress, - this.contactColor, + @required this.contactWrapper, }) : super( - isLoading: false, - isSuccess: true, - error: '', - ); + isLoading: false, + isSuccess: true, + error: '', + ); } class MessageItemStateFailure extends MessageItemState { MessageItemStateFailure({@required error}) : super( - isLoading: false, - isSuccess: false, - error: error, - ); + isLoading: false, + isSuccess: false, + error: error, + ); +} + +class ContactWrapper { + final int contactId; + final String contactName; + final String contactAddress; + final Color contactColor; + + ContactWrapper({ + @required this.contactId, + @required this.contactName, + @required this.contactAddress, + @required this.contactColor, + }); } class AttachmentWrapper { @@ -120,5 +130,4 @@ class AttachmentWrapper { @required this.size, @required this.type, }); - -} \ No newline at end of file +} diff --git a/lib/source/chat/messages_bloc.dart b/lib/source/message/messages_bloc.dart similarity index 95% rename from lib/source/chat/messages_bloc.dart rename to lib/source/message/messages_bloc.dart index 9c6ae02a..108b2359 100644 --- a/lib/source/chat/messages_bloc.dart +++ b/lib/source/message/messages_bloc.dart @@ -44,8 +44,8 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:delta_chat_core/delta_chat_core.dart'; -import 'package:ox_talk/source/chat/messages_event.dart'; -import 'package:ox_talk/source/chat/messages_state.dart'; +import 'package:ox_talk/source/message/messages_event.dart'; +import 'package:ox_talk/source/message/messages_state.dart'; import 'package:ox_talk/source/data/repository.dart'; import 'package:ox_talk/source/data/repository_manager.dart'; @@ -77,7 +77,7 @@ class MessagesBloc extends Bloc { } } else if (event is MessagesLoaded) { yield MessagesStateSuccess( - messageIds: messageRepository.getAllIds().reversed.toList(growable: false), + messageIds: messageRepository.getAllIds(), messageLastUpdateValues: messageRepository.getAllLastUpdateValues(), ); } diff --git a/lib/source/chat/messages_event.dart b/lib/source/message/messages_event.dart similarity index 100% rename from lib/source/chat/messages_event.dart rename to lib/source/message/messages_event.dart diff --git a/lib/source/chat/messages_state.dart b/lib/source/message/messages_state.dart similarity index 100% rename from lib/source/chat/messages_state.dart rename to lib/source/message/messages_state.dart diff --git a/pubspec.yaml b/pubspec.yaml index 94f7783f..40af198c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: OX Talk is a mail based chat app. version: 0.1.0+398 # x.y.z+build-number environment: - sdk: ">=2.0.0-dev.68.0 <3.0.0" + sdk: ">=2.1.0 <3.0.0" dependencies: flutter: From 5ec3c801ffa2ba4106ca4adb1363512430463bc3 Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Tue, 26 Feb 2019 17:52:26 +0100 Subject: [PATCH 11/13] OT-102 #5 Re-enable avatar selection in profile view --- lib/source/data/config.dart | 23 +++++- lib/source/profile/edit_user_settings.dart | 95 ++++++++++++++-------- lib/source/profile/profile.dart | 12 +-- lib/source/profile/user_bloc.dart | 25 +++--- lib/source/utils/widget.dart | 10 ++- 5 files changed, 108 insertions(+), 57 deletions(-) diff --git a/lib/source/data/config.dart b/lib/source/data/config.dart index fa93ac05..e8d8a417 100644 --- a/lib/source/data/config.dart +++ b/lib/source/data/config.dart @@ -47,7 +47,6 @@ class Config { Context _context = Context(); int _lastUpdate = -1; - String username; String status; String avatarPath; @@ -59,6 +58,8 @@ class Config { String smtpServer; int smtpPort; + int get lastUpdate => _lastUpdate; + Config._internal(); factory Config() { @@ -82,6 +83,11 @@ class Config { smtpLogin = await _context.getConfigValue(Context.configSendUser); smtpServer = await _context.getConfigValue(Context.configSendServer); smtpPort = await _context.getConfigValue(Context.configSendPort, ObjectType.int); + setLastUpdate(); + } + + void setLastUpdate() { + _lastUpdate = DateTime.now().millisecondsSinceEpoch; } reload() async { @@ -89,11 +95,15 @@ class Config { await load(); } - void setValue(String key, var value, [allowNullEmptyAndValues]) { - if (allowNullEmptyAndValues == null || !allowNullEmptyAndValues) { + void setValue(String key, var value, [bool allowNullAndEmptyValues, ObjectType enforceType]) { + if (allowNullAndEmptyValues == null || !allowNullAndEmptyValues) { if ((value == null || (value is String && value.isEmpty))) { return; } + } else { + if (enforceType == null) { + throw ArgumentError("allowNullAndEmptyValues is true but no specific type was set via enforceType."); + } } switch (key) { @@ -128,7 +138,12 @@ class Config { smtpPort = value; break; } - _context.setConfigValue(key, value); + if (enforceType != null) { + _context.setConfigValue(key, value, enforceType); + } else { + _context.setConfigValue(key, value); + } + setLastUpdate(); } String get smtpPortAsString => imapPort > 0 ? imapPort : ""; diff --git a/lib/source/profile/edit_user_settings.dart b/lib/source/profile/edit_user_settings.dart index 31bd4e96..5b2ea0fe 100644 --- a/lib/source/profile/edit_user_settings.dart +++ b/lib/source/profile/edit_user_settings.dart @@ -40,12 +40,12 @@ * for more details. */ -import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -//import 'package:image_picker_ui/image_picker_handler.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:image_cropper/image_cropper.dart'; import 'package:ox_talk/source/data/config.dart'; import 'package:ox_talk/source/l10n/localizations.dart'; import 'package:ox_talk/source/profile/user_bloc.dart'; @@ -53,7 +53,6 @@ import 'package:ox_talk/source/profile/user_event.dart'; import 'package:ox_talk/source/profile/user_state.dart'; import 'package:ox_talk/source/utils/colors.dart'; import 'package:ox_talk/source/utils/dimensions.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:rxdart/rxdart.dart'; class EditUserSettings extends StatefulWidget { @@ -61,24 +60,18 @@ class EditUserSettings extends StatefulWidget { _EditUserSettingsState createState() => _EditUserSettingsState(); } -class _EditUserSettingsState extends State with TickerProviderStateMixin {//, ImagePickerListener { +class _EditUserSettingsState extends State with TickerProviderStateMixin { UserBloc _userBloc = UserBloc(); TextEditingController _usernameController = TextEditingController(); TextEditingController _statusController = TextEditingController(); - File _image; - String _path = ""; - //ImagePickerHandler _imagePicker; + File _avatar; @override void initState() { super.initState(); _userBloc.dispatch(RequestUser()); - - //_imagePicker = new ImagePickerHandler(this, _controller); - //_imagePicker.build(0xFFEE6969,0xFFFFFFFF,false); - final userStatesObservable = new Observable(_userBloc.state); userStatesObservable.listen((state) => _handleUserStateChange(state)); } @@ -88,7 +81,10 @@ class _EditUserSettingsState extends State with TickerProvider Config config = state.config; _usernameController.text = config.username; _statusController.text = config.status; - _path = config.avatarPath; + String avatarPath = config.avatarPath; + if (avatarPath != null && avatarPath.isNotEmpty) { + _avatar = File(config.avatarPath); + } } } @@ -102,7 +98,7 @@ class _EditUserSettingsState extends State with TickerProvider ), backgroundColor: contactMain, title: Text(AppLocalizations.of(context).editUserSettingsTitle), - actions: [IconButton(icon: Icon(Icons.check), onPressed: saveChanges)], + actions: [IconButton(icon: Icon(Icons.check), onPressed: _saveChanges)], ), body: buildForm()); } @@ -129,13 +125,13 @@ class _EditUserSettingsState extends State with TickerProvider children: [ Padding(padding: EdgeInsets.only(top: 24.0)), new GestureDetector( - onTap: () => null,//_imagePicker.showDialog(context), + onTap: () => _showAvatarSourceChooser(), child: Stack( children: [ - _path.isNotEmpty + _avatar != null ? CircleAvatar( maxRadius: profileAvatarMaxRadius, - backgroundImage: FileImage(File('$_path')), + backgroundImage: FileImage(_avatar), ) : CircleAvatar( maxRadius: profileAvatarMaxRadius, @@ -177,31 +173,60 @@ class _EditUserSettingsState extends State with TickerProvider ); } - userImage(File _newImage) { - setState(() { - _image = _newImage; - _path = _newImage.path; - }); + _showAvatarSourceChooser() { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: Icon(Icons.photo), + title: Text("Gallery"), + onTap: () => _getNewAvatarPath(ImageSource.gallery), + ), + ListTile( + leading: Icon(Icons.camera_alt), + title: Text("Camera"), + onTap: () => _getNewAvatarPath(ImageSource.camera), + ), + ListTile( + leading: Icon(Icons.delete), + title: Text("Remove current image"), + onTap: () => _removeAvatar(), + ) + ], + ); + }); } - Future get _localPath async { - final directory = await getApplicationDocumentsDirectory(); - return directory.path; + _getNewAvatarPath(ImageSource source) async { + Navigator.pop(context); + File newAvatar = await ImagePicker.pickImage(source: source); + File croppedAvatar = await ImageCropper.cropImage( + sourcePath: newAvatar.path, + ratioX: 1.0, + ratioY: 1.0, + maxWidth: 512, + maxHeight: 512, + ); + if (croppedAvatar != null) { + setState(() { + _avatar = croppedAvatar; + }); + } } - Future saveImage(File image) async { - final path = await _localPath; - File newImage = await image.copy('$path/userAvatar.jpg'); - return newImage.path; + _removeAvatar() { + Navigator.pop(context); + setState(() { + _avatar = null; + }); } - void saveChanges() async { - if (_image != null) { - _path = await saveImage(_image); - } - - _userBloc.dispatch(UserPersonalDataChanged(username: _usernameController.text, status: _statusController.text, avatarPath: _path)); - + void _saveChanges() async { + String avatarPath = _avatar != null ? _avatar.path : null; + _userBloc.dispatch(UserPersonalDataChanged(username: _usernameController.text, status: _statusController.text, avatarPath: avatarPath)); Navigator.pop(context); } } diff --git a/lib/source/profile/profile.dart b/lib/source/profile/profile.dart index 7bc0477c..8696f571 100644 --- a/lib/source/profile/profile.dart +++ b/lib/source/profile/profile.dart @@ -125,7 +125,7 @@ class _ProfileState extends State { padding: EdgeInsets.symmetric(vertical: 24.0), child: buildAvatar(config), ), - getTextOrPlaceHolder( + buildTextOrPlaceHolder( text: config.username, style: TextStyle(fontSize: 24), align: TextAlign.center, @@ -142,7 +142,7 @@ class _ProfileState extends State { ), Padding( padding: const EdgeInsets.symmetric(vertical: 36.0), - child: getTextOrPlaceHolder( + child: buildTextOrPlaceHolder( text: config.status, align: TextAlign.center, style: TextStyle(fontSize: 16), @@ -163,8 +163,9 @@ class _ProfileState extends State { ); } - CircleAvatar buildAvatar(Config user) { - return user.avatarPath.isEmpty + CircleAvatar buildAvatar(Config config) { + var hasAvatarPath = config.avatarPath == null || config.avatarPath.isEmpty; + return hasAvatarPath ? CircleAvatar( maxRadius: profileAvatarMaxRadius, child: Icon( @@ -173,8 +174,9 @@ class _ProfileState extends State { ), ) : CircleAvatar( + key: createKey(config.lastUpdate), maxRadius: profileAvatarMaxRadius, - backgroundImage: FileImage(File(user.avatarPath)), + backgroundImage: FileImage(File(config.avatarPath)), ); } diff --git a/lib/source/profile/user_bloc.dart b/lib/source/profile/user_bloc.dart index fe48f7e3..58a3eb62 100644 --- a/lib/source/profile/user_bloc.dart +++ b/lib/source/profile/user_bloc.dart @@ -86,24 +86,25 @@ class UserBloc extends Bloc { dispatch(UserLoaded(config: config)); } - void _saveUserPersonalData(UserPersonalDataChanged event) { + void _saveUserPersonalData(UserPersonalDataChanged event) async { Config config = Config(); - config.setValue(Context.configDisplayName, event.username, true); - config.setValue(Context.configSelfStatus, event.status, true); - config.setValue(Context.configSelfAvatar, event.avatarPath, true); + config.setValue(Context.configDisplayName, event.username, true, ObjectType.String); + config.setValue(Context.configSelfStatus, event.status, true, ObjectType.String); + var avatarPath = event.avatarPath; + config.setValue(Context.configSelfAvatar, avatarPath, true, ObjectType.String); dispatch(UserChanged(config: config)); } void _saveUserAccountData(UserAccountDataChanged event) { Config config = Config(); - config.setValue(Context.configMailUser, event.imapLogin, true); - config.setValue(Context.configMailPassword, event.imapPassword, true); - config.setValue(Context.configMailServer, event.imapServer, true); - config.setValue(Context.configMailPort, event.imapPort, true); - config.setValue(Context.configSendUser, event.smtpLogin, true); - config.setValue(Context.configSendPassword, event.smtpPassword, true); - config.setValue(Context.configSendServer, event.smtpServer, true); - config.setValue(Context.configSendPort, event.smtpPort, true); + config.setValue(Context.configMailUser, event.imapLogin, true, ObjectType.String); + config.setValue(Context.configMailPassword, event.imapPassword, true, ObjectType.String); + config.setValue(Context.configMailServer, event.imapServer, true, ObjectType.String); + config.setValue(Context.configMailPort, event.imapPort, true, ObjectType.int); + config.setValue(Context.configSendUser, event.smtpLogin, true, ObjectType.String); + config.setValue(Context.configSendPassword, event.smtpPassword, true, ObjectType.String); + config.setValue(Context.configSendServer, event.smtpServer, true, ObjectType.String); + config.setValue(Context.configSendPort, event.smtpPort, true, ObjectType.int); dispatch(UserChanged(config: config)); } } diff --git a/lib/source/utils/widget.dart b/lib/source/utils/widget.dart index d48aeb27..e6f81889 100644 --- a/lib/source/utils/widget.dart +++ b/lib/source/utils/widget.dart @@ -42,6 +42,14 @@ import 'package:flutter/material.dart'; +Key createKey(var value) { + if (value is String) { + return Key(value); + } else { + return Key(value.toString()); + } +} + OutlineButton buildOutlineButton({ BuildContext context, Function onPressed, @@ -57,7 +65,7 @@ OutlineButton buildOutlineButton({ ); } -Widget getTextOrPlaceHolder({ +Widget buildTextOrPlaceHolder({ @required String text, TextStyle style, TextAlign align, From f51bd8aea2b3943cf4528afb4cb29d0247ae6b92 Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Fri, 1 Mar 2019 13:27:26 +0100 Subject: [PATCH 12/13] HOTFIX profile settings value problems fixed --- lib/main.dart | 4 +++- lib/source/profile/edit_user_settings.dart | 24 ++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c6bb8470..944ba862 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -46,6 +46,7 @@ import 'package:bloc/bloc.dart'; import 'package:delta_chat_core/delta_chat_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:ox_talk/source/data/config.dart'; import 'package:ox_talk/source/log/bloc_delegate.dart'; import 'package:ox_talk/source/chat/create_chat.dart'; import 'package:ox_talk/source/contact/contact_change.dart'; @@ -132,7 +133,8 @@ class _OxTalkState extends State<_OxTalk> { Future _setupDefaultValues() async { String status = await _context.getConfigValue(Context.configSelfStatus); if (status == AppLocalizations.of(context).deltaChatStatusDefaultValue) { - await _context.setConfigValue(Context.configSelfStatus, AppLocalizations.of(context).editUserSettingsStatusDefaultValue); + Config config = Config(); + config.setValue(Context.configSelfStatus, AppLocalizations.of(context).editUserSettingsStatusDefaultValue); } } diff --git a/lib/source/profile/edit_user_settings.dart b/lib/source/profile/edit_user_settings.dart index 5b2ea0fe..01a939dc 100644 --- a/lib/source/profile/edit_user_settings.dart +++ b/lib/source/profile/edit_user_settings.dart @@ -203,17 +203,19 @@ class _EditUserSettingsState extends State with TickerProvider _getNewAvatarPath(ImageSource source) async { Navigator.pop(context); File newAvatar = await ImagePicker.pickImage(source: source); - File croppedAvatar = await ImageCropper.cropImage( - sourcePath: newAvatar.path, - ratioX: 1.0, - ratioY: 1.0, - maxWidth: 512, - maxHeight: 512, - ); - if (croppedAvatar != null) { - setState(() { - _avatar = croppedAvatar; - }); + if (newAvatar != null) { + File croppedAvatar = await ImageCropper.cropImage( + sourcePath: newAvatar.path, + ratioX: 1.0, + ratioY: 1.0, + maxWidth: 512, + maxHeight: 512, + ); + if (croppedAvatar != null) { + setState(() { + _avatar = croppedAvatar; + }); + } } } From 180d30e3474de529f39da22c1cde5e8a4aadcf41 Mon Sep 17 00:00:00 2001 From: "daniel.boehrs" Date: Fri, 1 Mar 2019 14:24:39 +0100 Subject: [PATCH 13/13] HOTFIX message ordering in chat reversed --- lib/source/message/messages_bloc.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/source/message/messages_bloc.dart b/lib/source/message/messages_bloc.dart index 108b2359..d14c87c6 100644 --- a/lib/source/message/messages_bloc.dart +++ b/lib/source/message/messages_bloc.dart @@ -77,8 +77,8 @@ class MessagesBloc extends Bloc { } } else if (event is MessagesLoaded) { yield MessagesStateSuccess( - messageIds: messageRepository.getAllIds(), - messageLastUpdateValues: messageRepository.getAllLastUpdateValues(), + messageIds: messageRepository.getAllIds().reversed.toList(growable: false), + messageLastUpdateValues: messageRepository.getAllLastUpdateValues().reversed.toList(growable: false), ); } }