Skip to content

Commit e25fdf0

Browse files
committed
[windows] Implemented close and destroy method. #2
1 parent 34eefff commit e25fdf0

File tree

6 files changed

+140
-33
lines changed

6 files changed

+140
-33
lines changed

example/lib/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import './pages/home.dart';
66
void main() {
77
WidgetsFlutterBinding.ensureInitialized();
88

9+
localNotifier.setAppName('example');
10+
911
runApp(MyApp());
1012
}
1113

example/lib/pages/home.dart

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ class HomePage extends StatefulWidget {
1212
class _HomePageState extends State<HomePage> {
1313
LocalNotification? _exampleNotification = LocalNotification(
1414
identifier: '_exampleNotification',
15-
title: "local_notifier_example",
16-
subtitle: "example",
15+
title: "example",
1716
body: "hello flutter!",
1817
actions: [
1918
LocalNotificationAction(
20-
text: 'OK',
19+
text: 'Yes',
20+
),
21+
LocalNotificationAction(
22+
text: 'No',
2123
),
2224
],
2325
);
@@ -37,12 +39,15 @@ class _HomePageState extends State<HomePage> {
3739
_exampleNotification?.onClick = () {
3840
print('onClick ${_exampleNotification?.identifier}');
3941
};
42+
_exampleNotification?.onClickAction = (actionIndex) {
43+
print('onClickAction ${_exampleNotification?.identifier} - $actionIndex');
44+
};
4045
}
4146

4247
_handleNewLocalNotification() async {
4348
LocalNotification notification = LocalNotification(
44-
title: "local_notifier_example",
45-
subtitle: "example - ${_notificationList.length}",
49+
title: "example - ${_notificationList.length}",
50+
subtitle: "local_notifier_example",
4651
body: "hello flutter!",
4752
);
4853
notification.onShow = () {

lib/src/local_notification.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class LocalNotification with LocalNotificationListener {
2626
VoidCallback? onShow;
2727
VoidCallback? onClose;
2828
VoidCallback? onClick;
29+
ValueChanged<int>? onClickAction;
2930

3031
LocalNotification({
3132
String? identifier,
@@ -67,7 +68,7 @@ class LocalNotification with LocalNotificationListener {
6768
'subtitle': subtitle ?? '',
6869
'body': body ?? '',
6970
'silent': silent,
70-
'actions': actions?.map((e) => e.toJson()).toList(),
71+
'actions': (actions ?? []).map((e) => e.toJson()).toList(),
7172
}..removeWhere((key, value) => value == null);
7273
}
7374

@@ -109,4 +110,15 @@ class LocalNotification with LocalNotificationListener {
109110
}
110111
onClick!();
111112
}
113+
114+
@override
115+
void onLocalNotificationClickAction(
116+
LocalNotification notification,
117+
int actionIndex,
118+
) {
119+
if (identifier != notification.identifier || onClickAction == null) {
120+
return;
121+
}
122+
onClickAction!(actionIndex);
123+
}
112124
}

lib/src/local_notification_listener.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ abstract class LocalNotificationListener {
44
void onLocalNotificationShow(LocalNotification notification) {}
55
void onLocalNotificationClose(LocalNotification notification) {}
66
void onLocalNotificationClick(LocalNotification notification) {}
7+
void onLocalNotificationClickAction(
8+
LocalNotification notification,
9+
int actionIndex,
10+
) {}
711
}

lib/src/local_notifier.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:async';
2+
import 'dart:io';
23

34
import 'package:flutter/foundation.dart';
45
import 'package:flutter/services.dart';
@@ -19,6 +20,7 @@ class LocalNotifier {
1920
final ObserverList<LocalNotificationListener> _listeners =
2021
ObserverList<LocalNotificationListener>();
2122

23+
String? _appName;
2224
Map<String, LocalNotification> _notifications = {};
2325

2426
Future<void> _methodCallHandler(MethodCall call) async {
@@ -36,6 +38,12 @@ class LocalNotifier {
3638
listener.onLocalNotificationClose(localNotification!);
3739
} else if (call.method == 'onLocalNotificationClick') {
3840
listener.onLocalNotificationClick(localNotification!);
41+
} else if (call.method == 'onLocalNotificationClickAction') {
42+
int actionIndex = call.arguments['actionIndex'];
43+
listener.onLocalNotificationClickAction(
44+
localNotification!,
45+
actionIndex,
46+
);
3947
} else {
4048
throw UnimplementedError();
4149
}
@@ -60,11 +68,22 @@ class LocalNotifier {
6068
_listeners.remove(listener);
6169
}
6270

71+
void setAppName(String appName) {
72+
_appName = appName;
73+
}
74+
6375
/// Immediately shows the notification to the user.
6476
Future<void> notify(LocalNotification notification) async {
77+
if (Platform.isWindows && _appName == null) {
78+
throw Exception(
79+
'Missing appName, must call `localNotifier.setAppName` to set.',
80+
);
81+
}
82+
6583
_notifications[notification.identifier] = notification;
6684

6785
final Map<String, dynamic> arguments = notification.toJson();
86+
arguments['appName'] = _appName;
6887
await _channel.invokeMethod('notify', arguments);
6988
}
7089

windows/local_notifier_plugin.cpp

Lines changed: 92 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,51 @@
1616

1717
using namespace WinToastLib;
1818

19+
namespace {
20+
std::unique_ptr<
21+
flutter::MethodChannel<flutter::EncodableValue>,
22+
std::default_delete<flutter::MethodChannel<flutter::EncodableValue>>>
23+
channel = nullptr;
24+
1925
class CustomToastHandler : public IWinToastHandler {
2026
public:
21-
void toastActivated() const {}
27+
CustomToastHandler(std::string identifier);
28+
29+
void toastActivated() const {
30+
flutter::EncodableMap args = flutter::EncodableMap();
31+
args[flutter::EncodableValue("notificationId")] =
32+
flutter::EncodableValue(identifier);
33+
channel->InvokeMethod("onLocalNotificationClick",
34+
std::make_unique<flutter::EncodableValue>(args));
35+
}
2236

23-
void toastActivated(int actionIndex) const {}
37+
void toastActivated(int actionIndex) const {
38+
flutter::EncodableMap args = flutter::EncodableMap();
39+
args[flutter::EncodableValue("notificationId")] =
40+
flutter::EncodableValue(identifier);
41+
args[flutter::EncodableValue("actionIndex")] =
42+
flutter::EncodableValue(actionIndex);
43+
channel->InvokeMethod("onLocalNotificationClickAction",
44+
std::make_unique<flutter::EncodableValue>(args));
45+
}
2446

25-
void toastDismissed(WinToastDismissalReason state) const {}
47+
void toastDismissed(WinToastDismissalReason state) const {
48+
flutter::EncodableMap args = flutter::EncodableMap();
49+
args[flutter::EncodableValue("notificationId")] =
50+
flutter::EncodableValue(identifier);
51+
channel->InvokeMethod("onLocalNotificationClose",
52+
std::make_unique<flutter::EncodableValue>(args));
53+
}
2654

2755
void toastFailed() const {}
56+
57+
private:
58+
std::string identifier;
2859
};
2960

30-
namespace {
31-
std::unique_ptr<
32-
flutter::MethodChannel<flutter::EncodableValue>,
33-
std::default_delete<flutter::MethodChannel<flutter::EncodableValue>>>
34-
channel = nullptr;
61+
CustomToastHandler::CustomToastHandler(std::string identifier) {
62+
this->identifier = identifier;
63+
}
3564

3665
class LocalNotifierPlugin : public flutter::Plugin {
3766
public:
@@ -44,12 +73,15 @@ class LocalNotifierPlugin : public flutter::Plugin {
4473
private:
4574
flutter::PluginRegistrarWindows* registrar;
4675

47-
void LocalNotifierPlugin::_EmitEvent(std::string eventName);
76+
std::unordered_map<std::string, INT64> toast_id_map_ = {};
4877

4978
HWND LocalNotifierPlugin::GetMainWindow();
5079
void LocalNotifierPlugin::Notify(
5180
const flutter::MethodCall<flutter::EncodableValue>& method_call,
5281
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
82+
void LocalNotifierPlugin::Close(
83+
const flutter::MethodCall<flutter::EncodableValue>& method_call,
84+
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
5385

5486
// Called when a method is called on this plugin's channel from Dart.
5587
void HandleMethodCall(
@@ -78,14 +110,6 @@ LocalNotifierPlugin::LocalNotifierPlugin() {}
78110

79111
LocalNotifierPlugin::~LocalNotifierPlugin() {}
80112

81-
void LocalNotifierPlugin::_EmitEvent(std::string eventName) {
82-
flutter::EncodableMap args = flutter::EncodableMap();
83-
args[flutter::EncodableValue("eventName")] =
84-
flutter::EncodableValue(eventName);
85-
channel->InvokeMethod("onEvent",
86-
std::make_unique<flutter::EncodableValue>(args));
87-
}
88-
89113
HWND LocalNotifierPlugin::GetMainWindow() {
90114
return ::GetAncestor(registrar->GetView()->GetNativeWindow(), GA_ROOT);
91115
}
@@ -101,27 +125,66 @@ void LocalNotifierPlugin::Notify(
101125

102126
const flutter::EncodableMap& args =
103127
std::get<flutter::EncodableMap>(*method_call.arguments());
128+
129+
std::string appName =
130+
std::get<std::string>(args.at(flutter::EncodableValue("appName")));
131+
132+
std::string identifier =
133+
std::get<std::string>(args.at(flutter::EncodableValue("identifier")));
104134
std::string title =
105135
std::get<std::string>(args.at(flutter::EncodableValue("title")));
106-
std::string subtitle =
107-
std::get<std::string>(args.at(flutter::EncodableValue("subtitle")));
108136
std::string body =
109137
std::get<std::string>(args.at(flutter::EncodableValue("body")));
110138

111-
std::wstring appName = converter.from_bytes(title);
112-
std::wstring appUserModelID = converter.from_bytes(title);
139+
flutter::EncodableList actions = std::get<flutter::EncodableList>(
140+
args.at(flutter::EncodableValue("actions")));
113141

114-
WinToast::instance()->setAppName(appName);
115-
WinToast::instance()->setAppUserModelId(appUserModelID);
142+
WinToast::instance()->setAppName(converter.from_bytes(appName));
143+
WinToast::instance()->setAppUserModelId(converter.from_bytes(appName));
116144
WinToast::instance()->initialize();
117145

118146
WinToastTemplate toast = WinToastTemplate(WinToastTemplate::Text02);
119-
toast.setTextField(converter.from_bytes(subtitle),
120-
WinToastTemplate::FirstLine);
147+
toast.setTextField(converter.from_bytes(title), WinToastTemplate::FirstLine);
121148
toast.setTextField(converter.from_bytes(body), WinToastTemplate::SecondLine);
122149

123-
CustomToastHandler* handler = new CustomToastHandler();
124-
WinToast::instance()->showToast(toast, handler);
150+
for (flutter::EncodableValue action_value : actions) {
151+
flutter::EncodableMap action_map =
152+
std::get<flutter::EncodableMap>(action_value);
153+
std::string action_text =
154+
std::get<std::string>(action_map.at(flutter::EncodableValue("text")));
155+
156+
toast.addAction(converter.from_bytes(action_text));
157+
}
158+
159+
CustomToastHandler* handler = new CustomToastHandler(identifier);
160+
INT64 toast_id = WinToast::instance()->showToast(toast, handler);
161+
162+
toast_id_map_.insert(std::make_pair(identifier, toast_id));
163+
164+
flutter::EncodableMap args2 = flutter::EncodableMap();
165+
args2[flutter::EncodableValue("notificationId")] =
166+
flutter::EncodableValue(identifier);
167+
channel->InvokeMethod("onLocalNotificationShow",
168+
std::make_unique<flutter::EncodableValue>(args2));
169+
170+
result->Success(flutter::EncodableValue(true));
171+
}
172+
173+
void LocalNotifierPlugin::Close(
174+
const flutter::MethodCall<flutter::EncodableValue>& method_call,
175+
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
176+
const flutter::EncodableMap& args =
177+
std::get<flutter::EncodableMap>(*method_call.arguments());
178+
179+
std::string identifier =
180+
std::get<std::string>(args.at(flutter::EncodableValue("identifier")));
181+
182+
if (toast_id_map_.find(identifier) != toast_id_map_.end()) {
183+
INT64 toast_id = toast_id_map_.at(identifier);
184+
185+
WinToast::instance()->hideToast(toast_id);
186+
toast_id_map_.erase(identifier);
187+
}
125188

126189
result->Success(flutter::EncodableValue(true));
127190
}
@@ -131,6 +194,8 @@ void LocalNotifierPlugin::HandleMethodCall(
131194
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
132195
if (method_call.method_name().compare("notify") == 0) {
133196
Notify(method_call, std::move(result));
197+
} else if (method_call.method_name().compare("close") == 0) {
198+
Close(method_call, std::move(result));
134199
} else {
135200
result->NotImplemented();
136201
}

0 commit comments

Comments
 (0)