Files
sync_replay_project/apps/desktop/lib/src/widgets/copy_open.dart
T
foxyzandClaude Opus 5.5 4d00b7455e
ci / core (push) Successful in 27s
ci / server (push) Successful in 1m7s
ci / updater-windows (push) Failing after 6m4s
Restructure step 3: your server, Invite, version gate, AppGraph
- One server per app run (loopback, no password); Invite attaches an
  all-interfaces listener to the same server and Stop sharing detaches
  it (guests told with 4016); members, media and Up next never reset.
  No solo mode: you're home on your own server unless in a friend's.
- Navigation: none / yours / friend; a join passes a version gate on
  /health first (clear "they/you need to update", update offer).
- Invite as a value (host, port, name, password flag, version, fp
  reserved); addresses filtered (loopback, link-local, 198.18/15,
  bridges) and ranked; Sharing chip, Copy invite, Stop sharing.
- Alone looks like a plain player (alone replaces solo).
- AppGraph builds and disposes systems; widgets use AppScope;
  SessionState deleted; a test caps the remaining singletons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:52:52 +03:00

57 lines
1.9 KiB
Dart

import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import '../session/notifier.dart' show AppEvent, Copied, CopyFailed, noticeFor;
import '../app/app_graph.dart';
// Reusing what the app shows elsewhere: copying a link or a title, opening
// a page in the browser. One wording and one confirmation (a small toast)
// for every menu that offers them.
/// The labels of the reuse actions, the same in every menu.
abstract final class ReuseText {
static const copyLink = 'Copy link';
static const copyTitle = 'Copy title';
static const copyMessage = 'Copy message';
static const openInBrowser = 'Open in browser';
static const openInJellyfin = 'Open in Jellyfin';
}
/// Tests: where the confirmation goes instead of the session's toasts.
@visibleForTesting
void Function(String text)? debugReuseToast;
void Function(AppEvent event) _notifier(BuildContext context) {
final debug = debugReuseToast;
if (debug != null) return (event) => debug(noticeFor(event).toast ?? '');
return AppScope.of(context).notifier.notify;
}
/// Puts [text] on the clipboard and confirms it with a toast ([done]:
/// its text, e.g. "Link copied").
Future<void> copyToClipboard(BuildContext context, String text, {String done = 'Copied'}) async {
final notify = _notifier(context);
try {
await Clipboard.setData(ClipboardData(text: text));
} catch (_) {
notify(const CopyFailed());
return;
}
notify(Copied(done));
}
/// Opens [url] in the browser; when none opens, copies it instead and
/// says so.
Future<void> openLink(BuildContext context, String url) async {
final urls = AppScope.of(context).ports.urls;
final notify = _notifier(context);
if (await urls.open(url)) return;
try {
await Clipboard.setData(ClipboardData(text: url));
} catch (_) {
notify(const CopyFailed());
return;
}
notify(const Copied("Couldn't open a browser — link copied"));
}