[client] Working primary handoff

This commit is contained in:
Abhishek Shroff
2025-05-18 21:06:57 +05:30
parent 9a8f3863af
commit ad5bab0212
+78 -11
View File
@@ -1,4 +1,6 @@
import 'dart:async';
import 'dart:js_interop';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:offtheline/offtheline.dart';
@@ -6,6 +8,7 @@ import 'package:phylum/libphylum/phylum_account.dart';
import 'package:phylum/ui/app/dialog_scaffold.dart';
import 'package:phylum/ui/app/login_page.dart';
import 'package:phylum/ui/layout/app_layout.dart';
import 'package:phylum/util/logging.dart';
import 'package:provider/provider.dart';
import 'package:web/web.dart' as web;
@@ -23,12 +26,24 @@ class AccountSelector extends StatefulWidget {
}
class _AccountSelectorState extends State<AccountSelector> {
final channel = web.BroadcastChannel('takover');
final channel = web.BroadcastChannel('handoff');
late final AccountManager<PhylumAccount> accountManager;
String? requestId;
Timer? retryRequestTimer;
int retriesLeft = 0;
bool requestAccepted = false;
@override
void initState() {
super.initState();
channel.onmessage = processMessage.toJS;
accountManager = context.read();
}
@override
void dispose() {
channel.onmessage = null;
super.dispose();
}
@override
@@ -43,10 +58,8 @@ class _AccountSelectorState extends State<AccountSelector> {
const Text('Phylum is already open in another tab or window'),
const SizedBox(height: 12),
ElevatedButton(
onPressed: requestId == null ? requestHandoff : null,
child: const Text('Use Here'),
onPressed: () {
channel.postMessage('close'.toJS);
},
),
],
));
@@ -71,20 +84,74 @@ class _AccountSelectorState extends State<AccountSelector> {
return AppLayout.create(account);
}
void requestHandoff() {
if (requestId != null) return;
final r = Random();
const chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
setState(() {
requestId = String.fromCharCodes(Iterable.generate(12, (_) => chars.codeUnitAt(r.nextInt(chars.length))));
});
channel.postMessage('request|$requestId'.toJS);
retryRequestTimer = Timer.periodic(const Duration(milliseconds: 100), (t) {
if (retriesLeft-- > 0) {
if (!requestAccepted) {
channel.postMessage('request|$requestId'.toJS);
}
} else {
channel.postMessage('hijack|$requestId'.toJS);
retryRequestTimer?.cancel();
retryRequestTimer = null;
requestId = null;
setPrimary(true.toJS);
accountManager.initialize();
}
});
retriesLeft = 5;
requestAccepted = false;
}
void processMessage(web.MessageEvent event) {
final msg = event.data.toString();
final accountManager = context.read<AccountManager<PhylumAccount>>();
if (msg == 'close') {
final data = event.data.toString();
final msg = data.split('|');
if (msg.length < 2) {
logger.w('Unrecognized message: $data');
}
if (msg[0] == 'request') {
final id = msg[1];
if (accountManager.status == AccountManagerStatus.ready) {
channel.postMessage('closing'.toJS);
channel.postMessage('accept|$id'.toJS);
accountManager.close().then((v) {
channel.postMessage('closed'.toJS);
channel.postMessage('success|$id'.toJS);
setPrimary(false.toJS);
accountManager.close();
});
} else {
channel.postMessage('reject|$id'.toJS);
}
}
if (msg == 'closed') {
if (msg[0] == 'hijack') {
setPrimary(false.toJS);
}
// Process responses, but make sure the id matches
if (msg[1] != requestId) return;
if (msg[0] == 'reject') {
retryRequestTimer?.cancel();
retryRequestTimer = null;
requestId = null;
}
if (msg[0] == 'accept') {
// Maybe display a message if this is taking time
requestAccepted = true;
retriesLeft += 10;
}
if (msg[0] == 'success') {
retryRequestTimer?.cancel();
retryRequestTimer = null;
requestId = null;
setPrimary(true.toJS);
accountManager.initialize();
}