Skip to content
This repository has been archived by the owner on Oct 19, 2022. It is now read-only.

Commit

Permalink
Cleaned up and hardened BloC logic #501 OT-779
Browse files Browse the repository at this point in the history
Fixed method channel names
Fixed logger usage
Renamed notification_manager.dart to display_notification_manager.dart
Added async suffix
Updated libraries involved in push and notifications
Fixed some names and const declarations
  • Loading branch information
Boehrsi authored and Frank Gregor committed May 29, 2020
1 parent 0abac7e commit f7358a0
Show file tree
Hide file tree
Showing 24 changed files with 430 additions and 432 deletions.
6 changes: 3 additions & 3 deletions lib/src/chat/chat_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import 'package:ox_coi/src/data/repository_stream_handler.dart';
import 'package:ox_coi/src/extensions/color_apis.dart';
import 'package:ox_coi/src/l10n/l.dart';
import 'package:ox_coi/src/l10n/l10n.dart';
import 'package:ox_coi/src/notifications/notification_manager.dart';
import 'package:ox_coi/src/notifications/display_notification_manager.dart';

class ChatBloc extends Bloc<ChatEvent, ChatState> {
final _chatRepository = RepositoryManager.get(RepositoryType.chat);
Expand Down Expand Up @@ -205,7 +205,7 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
}

void _removeNotifications() {
final notificationManager = NotificationManager();
notificationManager.cancelNotification(_chatId);
final notificationManager = DisplayNotificationManager();
notificationManager.cancelNotificationAsync(_chatId);
}
}
6 changes: 3 additions & 3 deletions lib/src/contact/contact_change.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* for more details.
*/

import 'package:delta_chat_core/delta_chat_core.dart' as Core;
import 'package:delta_chat_core/delta_chat_core.dart' as dcc;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down Expand Up @@ -103,7 +103,7 @@ class _ContactChangeState extends State<ContactChange> {

ContactChangeBloc _contactChangeBloc = ContactChangeBloc();

Repository<Core.Chat> chatRepository;
Repository<dcc.Chat> chatRepository;

@override
void initState() {
Expand Down Expand Up @@ -133,7 +133,7 @@ class _ContactChangeState extends State<ContactChange> {
_navigation.pop(context);
} else {
if (state.id != null) {
Core.Context coreContext = Core.Context();
dcc.Context coreContext = dcc.Context();
var chatId = await coreContext.createChatByContactId(state.id);
chatRepository.putIfAbsent(id: chatId);
_navigation.pushAndRemoveUntil(
Expand Down
6 changes: 3 additions & 3 deletions lib/src/extensions/numbers_apis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import 'package:date_format/date_format.dart';
import 'package:ox_coi/src/l10n/l.dart';
import 'package:ox_coi/src/l10n/l10n.dart';

const _kilobyte = 1024;
const _megabyte = 1024 * _kilobyte;

extension Convert on int {
static const _kilobyte = 1024;
static const _megabyte = 1024 * _kilobyte;

String byteToPrintableSize() {
String unit;
double result;
Expand Down
11 changes: 6 additions & 5 deletions lib/src/invite/invite_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import 'package:ox_coi/src/invite/invite_service.dart';
import 'package:ox_coi/src/l10n/l.dart';
import 'package:ox_coi/src/l10n/l10n.dart';
import 'package:ox_coi/src/share/shared_data.dart';
import 'package:ox_coi/src/utils/constants.dart';
import 'package:ox_coi/src/utils/http.dart';
import 'package:ox_coi/src/utils/image.dart';
import 'package:path_provider/path_provider.dart';
Expand All @@ -68,7 +69,7 @@ import 'invite_event_state.dart';
class InviteBloc extends Bloc<InviteEvent, InviteState> {
final Repository<Contact> _contactRepository = RepositoryManager.get(RepositoryType.contact);
final Repository<Chat> _chatRepository = RepositoryManager.get(RepositoryType.chat);
static const platform = const MethodChannel(SharedData.sharingChannelName);
static const sharingChannel = const MethodChannel(kMethodChannelSharing);
InviteService inviteService = InviteService();

@override
Expand All @@ -92,7 +93,7 @@ class InviteBloc extends Bloc<InviteEvent, InviteState> {
Stream<InviteState> createInviteUrl(String message) async* {
InviteServiceRequest requestInviteService = await _createInviteServiceRequest(message ?? "");
var response = await inviteService.createInviteUrl(requestInviteService);
bool valid = validateHttpResponse(response);
bool valid = isHttpResponseValid(response);
if (valid) {
InviteServiceResponse responseInviteService = _getInviteResponse(response);
Map argsMap = <String, String>{
Expand All @@ -117,7 +118,7 @@ class InviteBloc extends Bloc<InviteEvent, InviteState> {
String id = sharedLink.substring(startIndex);
if (id.isNotEmpty) {
Response response = await inviteService.getInvite(id);
bool valid = validateHttpResponse(response);
bool valid = isHttpResponseValid(response);
if (valid) {
InviteServiceResponse responseInviteService = _getInviteResponse(response);
String imageString = responseInviteService.sender.image;
Expand Down Expand Up @@ -204,7 +205,7 @@ class InviteBloc extends Bloc<InviteEvent, InviteState> {
return inviteResponse;
}

Future<String> _getInitialLink() async => await platform.invokeMethod('getInitialLink');
Future<String> _getInitialLink() async => await sharingChannel.invokeMethod('getInitialLink');

void sendSharedData(Map argsMap) async => await platform.invokeMethod('sendSharedData', argsMap);
void sendSharedData(Map argsMap) async => await sharingChannel.invokeMethod('sendSharedData', argsMap);
}
2 changes: 1 addition & 1 deletion lib/src/invite/invite_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import 'package:ox_coi/src/utils/http.dart';
class InviteService {
static InviteService _instance;

var _logger = Logger("invite_service");
final _logger = Logger("invite_service");
var headers = {"Content-type": "application/json"};

factory InviteService() => _instance ??= InviteService._internal();
Expand Down
4 changes: 4 additions & 0 deletions lib/src/l10n/l.dart
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,10 @@ class L {
static final settingsAppearanceDescription = translationKey("Here you can choose your favorite theme. If you choose '%s', the theme may change automatically. This depends on whether you have selected 'Automatic' in the system preferences or not.");
static final settingsAppearanceSystemThemeDescription = translationKey("Current System theme is: %s");

static final notificationChannelTitle = _translationKey("Message notifications");
static final notificationChannelDescription = _translationKey("Notifications for incoming messages");

static List<String> _translationKey(String key, [String pluralKey]) {
static final dynamicScreenSkipButtonTitle = L.translationKey("Skip");
static final dynamicScreenBackButtonTitle = L.translationKey("Back");
static final dynamicScreenNextButtonTitle = L.translationKey("Next");
Expand Down
4 changes: 4 additions & 0 deletions lib/src/main/main_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import 'package:ox_coi/src/l10n/l.dart';
import 'package:ox_coi/src/l10n/l10n.dart';
import 'package:ox_coi/src/main/main_event_state.dart';
import 'package:ox_coi/src/notifications/local_notification_manager.dart';
import 'package:ox_coi/src/notifications/display_notification_manager.dart';
import 'package:ox_coi/src/platform/app_information.dart';
import 'package:ox_coi/src/platform/preferences.dart';
import 'package:ox_coi/src/push/push_bloc.dart';
Expand All @@ -74,6 +75,9 @@ import 'package:permission_handler/permission_handler.dart';

class MainBloc extends Bloc<MainEvent, MainState> {
final _logger = Logger("main_bloc");
final _notificationManager = DisplayNotificationManager();
final _pushManager = PushManager();
final _localNotificationManager = LocalNotificationManager();

Config _config = Config();
Context _context = Context();
Expand Down
5 changes: 2 additions & 3 deletions lib/src/message/message_attachment_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ import 'package:ox_coi/src/data/repository.dart';
import 'package:ox_coi/src/data/repository_manager.dart';
import 'package:ox_coi/src/extensions/numbers_apis.dart';
import 'package:ox_coi/src/message/message_attachment_event_state.dart';
import 'package:ox_coi/src/share/shared_data.dart';
import 'package:ox_coi/src/utils/constants.dart';
import 'package:ox_coi/src/utils/video.dart';
import 'package:path/path.dart';
import 'package:video_thumbnail/video_thumbnail.dart';

class MessageAttachmentBloc extends Bloc<MessageAttachmentEvent, MessageAttachmentState> {
static const platform = const MethodChannel(SharedData.sharingChannelName);
static const sharingChannel = const MethodChannel(kMethodChannelSharing);
final _logger = Logger("message_attachment_bloc");
Repository<Core.ChatMsg> _messageListRepository;

Expand Down Expand Up @@ -110,7 +109,7 @@ class MessageAttachmentBloc extends Bloc<MessageAttachmentEvent, MessageAttachme
var mime = filePath.isNotEmpty ? await message.getFileMime() : "text/*";

Map argsMap = <String, String>{'title': '$text', 'path': '$filePath', 'mimeType': '$mime', 'text': '$text'};
await platform.invokeMethod('sendSharedData', argsMap);
await sharingChannel.invokeMethod('sendSharedData', argsMap);
}

Core.ChatMsg _getMessage(int messageId) {
Expand Down
182 changes: 182 additions & 0 deletions lib/src/notifications/display_notification_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
* 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:delta_chat_core/delta_chat_core.dart' as dcc;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:ox_coi/src/chat/chat.dart';
import 'package:ox_coi/src/data/repository_manager.dart';
import 'package:ox_coi/src/extensions/string_apis.dart';
import 'package:ox_coi/src/l10n/l.dart';
import 'package:ox_coi/src/l10n/l10n.dart';
import 'package:ox_coi/src/lifecycle/lifecycle_bloc.dart';
import 'package:ox_coi/src/navigation/navigatable.dart';
import 'package:ox_coi/src/navigation/navigation.dart';
import 'package:ox_coi/src/utils/constants.dart';



class DisplayNotificationManager {
static const _androidIconPath = '@mipmap/ic_notification';
static const _payloadIdSeparator = "_";
static const _payloadChatIdPosition = 0;
static const _payloadMessageIdPosition = 1;

final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

final platformChannelSpecifics = NotificationDetails(
AndroidNotificationDetails(
kNotificationChannelMainId,
L10n.get(L.notificationChannelTitle),
L10n.get(L.notificationChannelDescription),
importance: Importance.Max,
priority: Priority.High,
),
IOSNotificationDetails(),
);

static DisplayNotificationManager _instance;

BuildContext _buildContext;

factory DisplayNotificationManager() => _instance ??= new DisplayNotificationManager._internal();

DisplayNotificationManager._internal();

Future<void> setupAsync(BuildContext buildContext) async {
this._buildContext = buildContext;
final initializationSettingsAndroid = AndroidInitializationSettings(_androidIconPath);
final initializationSettingsIOS = IOSInitializationSettings();
final initializationSettings = InitializationSettings(initializationSettingsAndroid, initializationSettingsIOS);
await _flutterLocalNotificationsPlugin.initialize(initializationSettings, onSelectNotification: onSelectNotification);
}

Future onSelectNotification(String payload) {
Navigation navigation = Navigation();
if (!payload.isNullOrEmpty()) {
int chatId = getIdFromPayload(payload, _payloadChatIdPosition);
int messageId = getIdFromPayload(payload, _payloadMessageIdPosition);
var isChatOpened = navigation.current?.equal(Navigatable(Type.chat, params: [chatId, messageId]));
if (isChatOpened == null || !isChatOpened) {
navigation.pushAndRemoveUntil(
_buildContext,
MaterialPageRoute(
builder: (context) {
return Chat(
chatId: chatId,
messageId: messageId,
headlessStart: true,
);
},
),
ModalRoute.withName(Navigation.root),
Navigatable(Type.rootChildren),
);
} else {
navigation.popUntilRoot(_buildContext);
}
} else {
navigation.popUntilRoot(_buildContext);
}
return Future.value(true);
}

int getIdFromPayload(String payload, int idPosition) {
var hasSeparator = payload.contains(_payloadIdSeparator);
if (!hasSeparator && idPosition > _payloadChatIdPosition) {
return null;
}
String idString = hasSeparator ? payload.split(_payloadIdSeparator)[idPosition] : payload;
return idString != null ? int.parse(idString) : null;
}

Future<void> showNotificationFromPushAsync(String fromEmail, String body) async {
if (_buildContext != null && _isAppResumed()) {
return;
}
final contactRepository = RepositoryManager.get<dcc.Contact>(RepositoryType.contact);
String name = fromEmail;
int chatId;
await Future.forEach(contactRepository.getAll(), (dcc.Contact contact) async {
final address = await contact.getAddress();
if (address == fromEmail) {
final contactName = await contact.getName();
name = contactName.isNotEmpty ? contactName : fromEmail;
final context = dcc.Context();
chatId = await context.getChatByContactId(contact.id);
}
});
await _flutterLocalNotificationsPlugin.show(chatId, name, body, platformChannelSpecifics, payload: chatId != 0 ? chatId.toString() : null);
}

Future<void> showNotificationFromLocalAsync(int chatId, String title, String body, {String payload}) async {
if (_buildContext != null) {
final navigation = Navigation();
if (_isAppInForeground(navigation)) {
final isChatOpened = navigation.current.equal(Navigatable(Type.chat, params: [chatId]));
final isChatListOpened = navigation.current.equal(Navigatable(Type.chatList));
if (isChatOpened || isChatListOpened) {
return;
}
}
}
await _flutterLocalNotificationsPlugin.show(chatId, title, body, platformChannelSpecifics, payload: payload);
}

bool _isAppInForeground(Navigation navigation) => navigation.hasElements() && _isAppResumed();

bool _isAppResumed() => BlocProvider.of<LifecycleBloc>(_buildContext).currentBackgroundState == AppLifecycleState.resumed.toString();

Future<bool> isAppLaunchedFromNotificationAsync() async {
final notificationAppLaunchDetails = await _flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
return notificationAppLaunchDetails.didNotificationLaunchApp;
}

Future<void> cancelNotificationAsync(int id) async {
await _flutterLocalNotificationsPlugin.cancel(id);
}

Future<dynamic> cancelAllNotificationsAsync() async {
await _flutterLocalNotificationsPlugin.cancelAll();
}
}
10 changes: 5 additions & 5 deletions lib/src/notifications/local_notification_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import 'package:ox_coi/src/data/chat_message_repository.dart';
import 'package:ox_coi/src/data/repository_manager.dart';
import 'package:ox_coi/src/l10n/l.dart';
import 'package:ox_coi/src/l10n/l10n.dart';
import 'package:ox_coi/src/notifications/notification_manager.dart';
import 'package:ox_coi/src/notifications/display_notification_manager.dart';
import 'package:ox_coi/src/platform/preferences.dart';
import 'package:rxdart/rxdart.dart';

Expand All @@ -64,7 +64,7 @@ class LocalNotificationManager {
final _core = DeltaChatCore();
final _context = Context();

NotificationManager _notificationManager;
DisplayNotificationManager _notificationManager;
bool _listenersRegistered = false;

factory LocalNotificationManager() => _instance ??= LocalNotificationManager._internal();
Expand All @@ -82,7 +82,7 @@ class LocalNotificationManager {
void _registerListeners() {
if (!_listenersRegistered) {
_listenersRegistered = true;
_notificationManager = NotificationManager();
_notificationManager = DisplayNotificationManager();
_messageSubject.listen(_messagesUpdated);
_core.addListener(eventIdList: [Event.incomingMsg, Event.msgsChanged], streamController: _messageSubject);
}
Expand Down Expand Up @@ -127,7 +127,7 @@ class LocalNotificationManager {
final teaser = await message.getSummaryText(200);
final payload = chatId?.toString();
_logger.info("Creating chat notification for chat id $chatId with message id $messageId");
_notificationManager.showNotificationFromLocal(chatId, title, teaser, payload: payload);
_notificationManager.showNotificationFromLocalAsync(chatId, title, teaser, payload: payload);
}
});

Expand Down Expand Up @@ -182,7 +182,7 @@ class LocalNotificationManager {
final teaser = await message.getSummaryText(200);
final payload = "${Chat.typeInvite.toString()}_$messageId";
_logger.info("Creating invite notification for sender id $senderId with message id $messageId");
_notificationManager.showNotificationFromLocal(Chat.typeInvite, title, teaser, payload: payload);
_notificationManager.showNotificationFromLocalAsync(Chat.typeInvite, title, teaser, payload: payload);
}
});

Expand Down
Loading

0 comments on commit f7358a0

Please sign in to comment.