Skip to content

Commit 8e9e52f

Browse files
committed
feat: Add focus hooks with metadata
1 parent af3987f commit 8e9e52f

File tree

10 files changed

+92
-26
lines changed

10 files changed

+92
-26
lines changed

analysis_options.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ linter:
1414
join_return_with_assignment: true
1515
prefer_for_elements_to_map_fromIterable: true
1616
null_check_on_nullable_type_parameter: true
17-
# yet to be released: document_ignores: true
17+
document_ignores: true

build.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
targets:
2+
$default:
3+
builders:
4+
freezed:
5+
enabled: true
6+
generate_for:
7+
exclude:
8+
- example
9+
options:
10+
format: true
11+
explicit_to_json: true

example/pubspec.lock

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ packages:
55
dependency: transitive
66
description:
77
name: args
8-
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
8+
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
99
url: "https://pub.dev"
1010
source: hosted
11-
version: "2.6.0"
11+
version: "2.7.0"
1212
async:
1313
dependency: transitive
1414
description:
@@ -77,10 +77,10 @@ packages:
7777
dependency: transitive
7878
description:
7979
name: ffi
80-
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
80+
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
8181
url: "https://pub.dev"
8282
source: hosted
83-
version: "2.1.3"
83+
version: "2.1.4"
8484
fixnum:
8585
dependency: transitive
8686
description:
@@ -108,7 +108,7 @@ packages:
108108
path: ".."
109109
relative: true
110110
source: path
111-
version: "1.2.3"
111+
version: "1.2.4"
112112
flutter_test:
113113
dependency: "direct dev"
114114
description: flutter
@@ -142,18 +142,18 @@ packages:
142142
dependency: transitive
143143
description:
144144
name: grpc
145-
sha256: "5b99b7a420937d4361ece68b798c9af8e04b5bc128a7859f2a4be87427694813"
145+
sha256: "751635443218cc81d2120e566e47567d4e033a10f99de859f21b65eefcad8488"
146146
url: "https://pub.dev"
147147
source: hosted
148-
version: "4.0.1"
148+
version: "4.0.3"
149149
http:
150150
dependency: transitive
151151
description:
152152
name: http
153-
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
153+
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
154154
url: "https://pub.dev"
155155
source: hosted
156-
version: "1.2.2"
156+
version: "1.3.0"
157157
http2:
158158
dependency: transitive
159159
description:
@@ -262,10 +262,10 @@ packages:
262262
dependency: transitive
263263
description:
264264
name: path_provider_android
265-
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
265+
sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12"
266266
url: "https://pub.dev"
267267
source: hosted
268-
version: "2.2.15"
268+
version: "2.2.16"
269269
path_provider_foundation:
270270
dependency: transitive
271271
description:
@@ -443,10 +443,10 @@ packages:
443443
dependency: transitive
444444
description:
445445
name: web
446-
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
446+
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
447447
url: "https://pub.dev"
448448
source: hosted
449-
version: "1.1.0"
449+
version: "1.1.1"
450450
window_manager:
451451
dependency: transitive
452452
description:
@@ -464,5 +464,5 @@ packages:
464464
source: hosted
465465
version: "1.1.0"
466466
sdks:
467-
dart: ">=3.7.0-0 <4.0.0"
468-
flutter: ">=3.24.0"
467+
dart: ">=3.7.0 <4.0.0"
468+
flutter: ">=3.27.0"

lib/flutter_single_instance.dart

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ library flutter_single_instance;
3131

3232
export 'package:window_manager/window_manager.dart' show windowManager;
3333

34+
import 'dart:async';
3435
import 'dart:convert';
3536
import 'dart:io';
3637
import 'package:flutter/foundation.dart';
@@ -81,6 +82,17 @@ abstract class FlutterSingleInstance {
8182
/// Defaults to [kDebugMode].
8283
static bool debugMode = kDebugMode;
8384

85+
/// Called before this instance is focused with metadata provided by the calling instance.
86+
///
87+
/// ```dart
88+
/// FlutterSingleInstance.onFocus = (metadata) {
89+
/// print("Focused instance with metadata: $metadata"); // "Focused instance with metadata: {hello: world}"
90+
/// };
91+
///
92+
/// FlutterSingleInstance().focus({"hello": "world"});
93+
/// ```
94+
static FutureOr<void> Function(Map<String, dynamic>)? onFocus;
95+
8496
/// Retrieves the process name of the given [pid].
8597
/// Returns [null] if the process does not exist.
8698
Future<String?> getProcessName(int pid);
@@ -190,9 +202,10 @@ abstract class FlutterSingleInstance {
190202
return _server!.port!;
191203
}
192204

193-
/// Focuses the running instance of the app and
194-
/// returns `null` if the operation was successful or an error message if it failed.
195-
Future<String?> focus() async {
205+
/// Focuses the running instance of the app and returns `null` if the operation was successful or an error message if it failed.
206+
///
207+
/// The [metadata] parameter is passed to the focused instance's [onFocus] callback.
208+
Future<String?> focus([Object? metadata]) async {
196209
if (_instance == null) return "No instance to focus";
197210
if (_server != null) return "This is the first instance";
198211

@@ -213,9 +226,15 @@ abstract class FlutterSingleInstance {
213226
),
214227
);
215228

229+
if (metadata == null) {
230+
metadata = <String, dynamic>{};
231+
}
232+
final json = jsonEncode(metadata);
233+
final binary = utf8.encode(json);
234+
216235
final client = FocusServiceClient(channel);
217236

218-
final response = await client.focus(FocusRequest());
237+
final response = await client.focus(FocusRequest(metadata: binary));
219238

220239
if (response.success) {
221240
logger.finest("Instance focused");

lib/src/focus.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:convert';
2+
13
import 'package:flutter_single_instance/flutter_single_instance.dart';
24
import 'package:flutter_single_instance/src/generated/focus.pbgrpc.dart';
35
import 'package:grpc/grpc.dart';
@@ -6,11 +8,25 @@ import 'package:grpc/grpc.dart';
68
class FocusService extends FocusServiceBase {
79
@override
810
Future<FocusResponse> focus(ServiceCall call, FocusRequest request) async {
11+
// whe're still in the same package and should log with the same logger
912
// ignore: invalid_use_of_protected_member
1013
final logger = FlutterSingleInstance().logger;
1114

1215
logger.finest('Received focus request from another instance');
1316

17+
if (FlutterSingleInstance.onFocus != null) {
18+
try {
19+
final metadata =
20+
jsonDecode(utf8.decode(request.metadata)) as Map<String, dynamic>;
21+
22+
await FlutterSingleInstance.onFocus!(metadata);
23+
24+
logger.finest('onFocus hook executed with $metadata');
25+
} catch (e, s) {
26+
logger.finest('Failed to run onFocus hook', e, s);
27+
}
28+
}
29+
1430
try {
1531
await windowManager.focus();
1632

lib/src/generated/focus.pb.dart

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/generated/focus.pbjson.dart

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/unsupported.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Unsupported extends FlutterSingleInstance {
1717
Future<File?> getPidFile(String processName) async => null;
1818

1919
@override
20-
Future<String?> focus() async => null;
20+
Future<String?> focus([Object? metadata]) async => null;
2121

2222
@override
2323
Future<void> activateInstance(String processName) async {}

protos/focus.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ service FocusService {
66
rpc Focus(FocusRequest) returns (FocusResponse) {}
77
}
88

9-
message FocusRequest {}
9+
message FocusRequest { bytes metadata = 1; }
1010

1111
message FocusResponse {
1212
bool success = 1;

pubspec.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ platforms:
1111
android:
1212
web:
1313
environment:
14-
sdk: ">=2.16.2 <4.0.0"
15-
flutter: ">=1.17.0"
14+
sdk: ">=3.0.0 <4.0.0"
1615

1716
dependencies:
1817
flutter:

0 commit comments

Comments
 (0)