Skip to content

Commit

Permalink
feat(notifications): notify the configuration of local storage
Browse files Browse the repository at this point in the history
  • Loading branch information
colinin committed Jul 16, 2023
1 parent 9123fb2 commit 8219366
Show file tree
Hide file tree
Showing 18 changed files with 503 additions and 109 deletions.
49 changes: 48 additions & 1 deletion apps/flutter/core/lib/config/env.config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class EnvConfig {
this.staticFilesUrl,
this.tenantKey = '__tenant',
this.defaultLanguage = 'en',
this.notifications,
});
String clientId;
String? clientSecret;
Expand All @@ -24,10 +25,56 @@ class EnvConfig {
String? staticFilesUrl;
String? tenantKey;
String? defaultLanguage;
NotificationConfig? notifications;

factory EnvConfig.fromJson(Map<String, dynamic> json) => _$EnvConfigFromJson(json);
}

@JsonSerializable(createToJson: false)
class NotificationConfig {
NotificationConfig({
this.android,
this.darwin,
this.linux,
});
AndroidNotification? android;
DarwinNotification? darwin;
LinuxNotification? linux;

factory NotificationConfig.fromJson(Map<String, dynamic> json) => _$NotificationConfigFromJson(json);
}

@JsonSerializable(createToJson: false)
class LinuxNotification {
LinuxNotification({
required this.defaultActionName,
});
String defaultActionName;

factory LinuxNotification.fromJson(Map<String, dynamic> json) => _$LinuxNotificationFromJson(json);
}

@JsonSerializable(createToJson: false)
class AndroidNotification {
AndroidNotification({
required this.channelId,
required this.channelName,
this.channelDescription,
});
String channelId;
String channelName;
String? channelDescription;

factory AndroidNotification.fromJson(Map<String, dynamic> json) => _$AndroidNotificationFromJson(json);
}

@JsonSerializable(createToJson: false)
class DarwinNotification {
DarwinNotification();

factory DarwinNotification.fromJson(Map<String, dynamic> json) => _$DarwinNotificationFromJson(json);
}

enum Env {
development('DEV', 'Development'),
profile('PROF', 'Profile'),
Expand All @@ -53,7 +100,7 @@ class Environment {
fromJson: EnvConfig.fromJson,
);

Environment.current = envlib.Environment.instance().config;
Environment.current = envlib.Environment<EnvConfig>.instance().config;
}

static late EnvConfig current;
Expand Down
37 changes: 35 additions & 2 deletions apps/flutter/core/lib/config/env.config.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions apps/flutter/core/lib/models/abp.dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ class LocalizableStringInfo {
LocalizableStringInfo({
required this.resourceName,
required this.name,
this.values,
});
String resourceName;
String name;
Map<String, dynamic>? values;

factory LocalizableStringInfo.fromJson(Map<String, dynamic> json) =>
LocalizableStringInfo(
resourceName: json['resourceName'] as String,
name: json['name'] as String,
values: json['values'] as Map<String, dynamic>?,
);
Map<String, dynamic> toJson() => <String, dynamic>{
'resourceName': resourceName,
'name': name,
'values': values,
};
}

Expand Down
2 changes: 1 addition & 1 deletion apps/flutter/core/lib/services/service.base.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:get/get.dart';

abstract class ServiceBase extends GetxService {
T find<T>() => Get.find<T>();
T find<T>({ String? tag}) => Get.find<T>(tag: tag);
}
13 changes: 13 additions & 0 deletions apps/flutter/core/lib/utils/localization.utils.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:core/utils/string.extensions.dart';
import 'package:get/get.dart';

import '../proxy/volo/abp/asp-net-core/mvc/index.dart';

Expand Down Expand Up @@ -64,4 +65,16 @@ class LocalizedText {
String? resourceName;
String? key;
String? localized;
}

extension AbpTranslationsExtensions on String {
String trFormat([Map<String, String> params = const {}]) {
var trans = tr;
if (params.isNotEmpty) {
params.forEach((key, value) {
trans = trans.replaceAll('{$key}', value);
});
}
return trans;
}
}
42 changes: 42 additions & 0 deletions apps/flutter/dev_app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,45 @@ A few resources to get you started if this is your first Flutter project:
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

## Environment

* **baseUrl**: 服务器连接地址(必输)
* **clientId**: 客户端标识(必输)
* **clientSecret**: 客户端密钥(可选)
* **authority**: 身份认证服务器地址(必输)
* **uploadFilesUrl**: 上传文件路径(可选)
* **staticFilesUrl**: 静态文件路径(可选)
* **tenantKey**: 多租户标识(可选)
* **defaultLanguage**: 应用程序默认语言, 优先级低于用户配置(可选)
* **notifications**: 通知相关设置(可选)
* ***android***: android端通知设置(可选)
* ***channelId***: 通道标识(配置了android节点后为必输)
* ***channelName***: 通道名称(配置了android节点后为必输)
* ***channelDescription***: 通道说明(可选)
* ***linux***: linux端通知设置(可选)
* ***defaultActionName***: 默认点击方法名称(配置了linux节点后为必输)
* ***darwin***: iOS/Mac os端通知设置(可选)

```json
{
"baseUrl": "http://127.0.0.1:30000",
"clientId": "abp-flutter",
"clientSecret": "1q2w3e*",
"authority": "http://127.0.0.1:30000",
"uploadFilesUrl": "",
"staticFilesUrl": "",
"tenantKey": "__tenant",
"defaultLanguage": "en",
"notifications": {
"android": {
"channelId": "abp-flutter",
"channelName": "abp-flutter",
"channelDescription": "适用于Android端的通知通道定义"
},
"linux": {
"defaultActionName": "Open notification"
}
}
}
```
55 changes: 34 additions & 21 deletions apps/flutter/dev_app/lib/pages/main/controller.dart
Original file line number Diff line number Diff line change
@@ -1,52 +1,65 @@
import 'package:core/services/notification.send.service.dart';
import 'package:get/get.dart';
import 'package:core/config/index.dart';
import 'package:core/services/config.state.service.dart';
import 'package:core/services/session.service.dart';
import 'package:core/services/signalr.service.dart';
import 'package:core/services/subscription.service.dart';
import 'package:core/tokens/index.dart';
import 'package:core/utils/index.dart';
import 'package:notifications/models/notification.dart';
import 'package:notifications/models/index.dart';

class MainController extends GetxController {
final RxInt _pageIndex = RxInt(0);
int get currentIndex => _pageIndex.value;

SessionService get sessionService => Get.find();
ConfigStateService get configStateService => Get.find();
SubscriptionService get subscriptionService => Get.find(tag: NotificationTokens.consumer);
SignalrService get signalrService => Get.find(tag: NotificationTokens.producer);
SessionService get _sessionService => Get.find();
SubscriptionService get _subscriptionService => Get.find(tag: NotificationTokens.consumer);
SignalrService get _signalrService => Get.find(tag: NotificationTokens.producer);
NotificationSendService get _notificationSendService => Get.find();

@override
void onInit() async {
super.onInit();
subscriptionService.addOne(signalrService.onClose(logger.debug));
subscriptionService.addOne(signalrService.onReconnected(logger.debug));
subscriptionService.addOne(signalrService.onReconnecting(logger.debug));
subscriptionService.subscribe(
signalrService.subscribe(NotificationTokens.receiver),
(message) {
var notification = NotificationInfo.fromJson(message.data.first as dynamic);
logger.debug(notification);
_subscriptionService.addOne(_signalrService.onClose(logger.debug));
_subscriptionService.addOne(_signalrService.onReconnected(logger.debug));
_subscriptionService.addOne(_signalrService.onReconnecting(logger.debug));
// 在SignalR Hub之上再次订阅,用于全局通知启用按钮来管理
_subscriptionService.subscribe(
// 订阅SignalR Hub
_signalrService.subscribe(NotificationTokens.receiver),
(message) async {
for (var data in message.data) {
if (data == null) continue;
// 解析通知数据
var notification = NotificationInfo.fromJson(data as dynamic);
// 格式化为移动端可识别通知数据
var payload = NotificationPaylod.fromData(notification.data);
// 发布本地通知
await _notificationSendService.send(
payload.title,
payload.body,
payload.payload,
);
}
},
);
sessionService.getToken$()
_sessionService.getToken$()
.listen((token) async {
if (token == null) {
await signalrService.stop();
await _signalrService.stop();
} else {
await signalrService.start();
await _signalrService.start();
}
});
if (sessionService.currentLanguage.isNullOrWhiteSpace()) {
sessionService.setLanguage(Environment.current.defaultLanguage ?? 'en');
if (_sessionService.currentLanguage.isNullOrWhiteSpace()) {
_sessionService.setLanguage(Environment.current.defaultLanguage ?? 'en');
}
}

@override
void onClose() {
subscriptionService.closeAll()
.whenComplete(() => signalrService.stop());
_subscriptionService.closeAll()
.whenComplete(() => _signalrService.stop());
super.onClose();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'package:core/config/index.dart';
import 'package:get/get.dart';
import 'package:rxdart/rxdart.dart' hide Notification;

Expand All @@ -11,11 +12,12 @@ class FlutterLocalNotificationsSendService extends NotificationSendService {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
final Subject<Notification> _notifications$ = BehaviorSubject<Notification>();
final Subject<String?> _selectedNotifications$ = BehaviorSubject<String?>();
final EnvConfig _env = Environment.current;

Future<void> initAsync() async {
const initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/logo');
const initializationSettingsLinux = LinuxInitializationSettings(
defaultActionName: 'Open notification',
var initializationSettingsLinux = LinuxInitializationSettings(
defaultActionName: _env.notifications?.linux?.defaultActionName ?? 'Open notification',
);
var initializationSettingsDarwin = DarwinInitializationSettings(
onDidReceiveLocalNotification: (id, title, body, payload) {
Expand Down Expand Up @@ -46,17 +48,28 @@ class FlutterLocalNotificationsSendService extends NotificationSendService {
@override
Future<void> send(String title, [String? body, String? payload]) async {
nid.value += 1;
const androidDetails = AndroidNotificationDetails(
'abp-flutter',
'abp-flutter');
const details = NotificationDetails(

await _flutterLocalNotificationsPlugin.show(
nid.value, title, body, _buildDetails(), payload: payload);
}

NotificationDetails _buildDetails() {
var androidDetails = AndroidNotificationDetails(
_env.notifications?.android?.channelId ?? 'abp-flutter',
_env.notifications?.android?.channelName ?? 'abp-flutter',
channelDescription: _env.notifications?.android?.channelDescription);

const darwinDetails = DarwinNotificationDetails();

const linuxDetails = LinuxNotificationDetails();

var details = NotificationDetails(
android: androidDetails,
iOS: darwinDetails,
macOS: darwinDetails,
linux: linuxDetails,
);
await _flutterLocalNotificationsPlugin.show(
nid.value,
title,
body,
details,
payload: payload);

return details;
}
}
12 changes: 11 additions & 1 deletion apps/flutter/dev_app/res/config/demo.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,15 @@
"uploadFilesUrl": "",
"staticFilesUrl": "",
"tenantKey": "__tenant",
"defaultLanguage": "en"
"defaultLanguage": "en",
"notifications": {
"android": {
"channelId": "abp-flutter",
"channelName": "abp-flutter",
"channelDescription": "适用于Android端的通知通道定义"
},
"linux": {
"defaultActionName": "Open notification"
}
}
}
Loading

0 comments on commit 8219366

Please sign in to comment.