Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions lib/features/midi/providers/midi_connection_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class MidiConnectionNotifier extends Notifier<MidiConnectionState> {
static const Duration _findTargetTimeout = Duration(seconds: 8);
static const Duration _reconnectAttemptTimeout = Duration(seconds: 12);
static const Duration _connectedPublishTimeout = Duration(seconds: 3);
static const Duration _longBackgroundReconnectThreshold = Duration(
minutes: 3,
);
static const bool _debugLog = midiDebug;

bool _startupAttempted = false;
Expand All @@ -34,6 +37,8 @@ class MidiConnectionNotifier extends Notifier<MidiConnectionState> {

bool _backgrounded = false;
bool _attemptInFlight = false;
DateTime? _backgroundBeganAt;
Duration? _lastBackgroundDuration;

// Dedupe guard: prevents repeated persistence writes when the
// connected-device stream re-emits the same device id.
Expand Down Expand Up @@ -211,8 +216,20 @@ class MidiConnectionNotifier extends Notifier<MidiConnectionState> {
}

void setBackgrounded(bool value) {
if (_backgrounded == value) {
return;
}
_backgrounded = value;
if (_debugLog) debugPrint('[CONN] backgrounded=$_backgrounded');
if (_backgrounded) {
_backgroundBeganAt = DateTime.now();
} else {
final beganAt = _backgroundBeganAt;
_backgroundBeganAt = null;
_lastBackgroundDuration = beganAt == null
? null
: DateTime.now().difference(beganAt);
}
if (_backgrounded) {
// Controller-owned policy: background cancels attempts and stops scanning.
unawaited(cancel(reason: 'background'));
Expand Down Expand Up @@ -301,13 +318,19 @@ class MidiConnectionNotifier extends Notifier<MidiConnectionState> {

// If already connected to the last connected device, do nothing.
final current = ref.read(midiDeviceManagerProvider).connectedDevice;
final forceResumeReconnect =
reason == 'resume' &&
(_lastBackgroundDuration ?? Duration.zero) >=
_longBackgroundReconnectThreshold;
if (current?.id == lastConnectedDeviceId &&
current?.isConnected == true) {
final stillConnected = await _withTimeout(
_midi.isStillConnected(lastConnectedDeviceId),
timeout: const Duration(seconds: 2),
onTimeout: false,
);
final stillConnected = forceResumeReconnect
? false
: await _withTimeout(
_midi.isStillConnected(lastConnectedDeviceId),
timeout: const Duration(seconds: 2),
onTimeout: false,
);
if (stillConnected == true) {
if (_debugLog) {
debugPrint('[CONN] stillConnected id=$lastConnectedDeviceId');
Expand Down
9 changes: 6 additions & 3 deletions lib/features/midi/providers/midi_device_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ class MidiDeviceManager extends Notifier<MidiDeviceManagerState> {
bool scanIfNeeded = false,
}) {
final inflight = _reconcileInFlight;
if (inflight != null) return inflight;
if (inflight != null) {
return inflight;
}

if (_debugLog) {
debugPrint(
Expand All @@ -365,7 +367,9 @@ class MidiDeviceManager extends Notifier<MidiDeviceManagerState> {
required bool scanIfNeeded,
}) async {
final current = state.connectedDevice;
if (current == null) return;
if (current == null) {
return;
}

try {
// If we believe we are connected, it is reasonable to prime the central
Expand Down Expand Up @@ -527,7 +531,6 @@ class MidiDeviceManager extends Notifier<MidiDeviceManagerState> {
'connected=${state.connectedDevice?.id}/${state.connectedDevice?.isConnected}',
);
}

state = state.copyWith(devices: devices);
_signalDevicesChanged();

Expand Down
Loading