diff --git a/lib/builtin/decisions/src/decision_detail_view.dart b/lib/builtin/decisions/src/decision_detail_view.dart index 8d0a446a..13d00e5c 100644 --- a/lib/builtin/decisions/src/decision_detail_view.dart +++ b/lib/builtin/decisions/src/decision_detail_view.dart @@ -2,39 +2,31 @@ import 'dart:async'; import 'package:clide/builtin/decisions/src/decision_colors.dart'; import 'package:clide/kernel/kernel.dart'; -import 'package:clide/kernel/src/events/message_bus.dart'; import 'package:clide/widgets/widgets.dart'; import 'package:flutter/widgets.dart'; class DecisionDetailView extends StatefulWidget { - const DecisionDetailView({super.key}); + const DecisionDetailView({super.key, this.initialId}); + final String? initialId; @override State createState() => _DecisionDetailViewState(); } class _DecisionDetailViewState extends State { - StreamSubscription? _sub; Map? _decision; bool _loading = false; @override void didChangeDependencies() { super.didChangeDependencies(); - if (_sub != null) return; - final kernel = ClideKernel.of(context); - _sub = kernel.messages.subscribe(publisher: 'builtin.decisions', channel: 'selection').listen((msg) { - final id = msg.data['id'] as String?; - if (id != null) { - kernel.panels.activateTab(Slots.contextPanel, 'decisions.detail'); - unawaited(_load(id)); - } - }); + if (widget.initialId != null && _decision == null && !_loading) { + unawaited(_load(widget.initialId!)); + } } @override void dispose() { - _sub?.cancel(); super.dispose(); } diff --git a/lib/builtin/decisions/src/extension.dart b/lib/builtin/decisions/src/extension.dart index 4f76a978..dec06b9f 100644 --- a/lib/builtin/decisions/src/extension.dart +++ b/lib/builtin/decisions/src/extension.dart @@ -5,6 +5,7 @@ import 'package:clide/builtin/decisions/src/decisions_view.dart'; import 'package:clide/extension/extension.dart'; import 'package:clide/kernel/kernel.dart'; import 'package:clide/kernel/src/events/message_bus.dart'; +import 'package:flutter/foundation.dart' show VoidCallback; class DecisionsExtension extends ClideExtension { @override @@ -18,6 +19,7 @@ class DecisionsExtension extends ClideExtension { ClideExtensionContext? _ctx; StreamSubscription? _selectionSub; + VoidCallback? _panelListener; bool _detailSpawned = false; @override @@ -37,27 +39,38 @@ class DecisionsExtension extends ClideExtension { Future activate(ClideExtensionContext ctx) async { _ctx = ctx; _selectionSub = ctx.messages.subscribe(publisher: id, channel: 'selection').listen(_onSelection); + _panelListener = () { + if (_detailSpawned && ctx.panels.activeTabIn(Slots.contextPanel) != 'decisions.detail') { + _despawnDetail(); + } + }; + ctx.panels.addListener(_panelListener!); } @override Future deactivate() async { _selectionSub?.cancel(); + if (_panelListener != null) _ctx?.panels.removeListener(_panelListener!); _despawnDetail(); } void _onSelection(Message msg) { final ctx = _ctx; if (ctx == null) return; - if (!_detailSpawned) { - ctx.panels.contribute(TabContribution( - id: 'decisions.detail', - slot: Slots.contextPanel, - title: 'Decision', - priority: -50, - build: (_) => const DecisionDetailView(), - )); - _detailSpawned = true; + final selectedId = msg.data['id'] as String?; + if (selectedId == null) return; + + if (_detailSpawned) { + _despawnDetail(); } + ctx.panels.contribute(TabContribution( + id: 'decisions.detail', + slot: Slots.contextPanel, + title: 'Decision', + priority: -50, + build: (_) => DecisionDetailView(initialId: selectedId), + )); + _detailSpawned = true; ctx.panels.activateTab(Slots.contextPanel, 'decisions.detail'); } diff --git a/lib/builtin/tickets/src/extension.dart b/lib/builtin/tickets/src/extension.dart index a1db09e2..f8076e97 100644 --- a/lib/builtin/tickets/src/extension.dart +++ b/lib/builtin/tickets/src/extension.dart @@ -5,6 +5,7 @@ import 'package:clide/builtin/tickets/src/tickets_view.dart'; import 'package:clide/extension/extension.dart'; import 'package:clide/kernel/kernel.dart'; import 'package:clide/kernel/src/events/message_bus.dart'; +import 'package:flutter/foundation.dart' show VoidCallback; class TicketsExtension extends ClideExtension { @override @@ -12,12 +13,13 @@ class TicketsExtension extends ClideExtension { @override String get title => 'Tickets'; @override - String get version => '0.3.0'; + String get version => '0.4.0'; @override List get dependsOn => const []; ClideExtensionContext? _ctx; StreamSubscription? _selectionSub; + VoidCallback? _panelListener; bool _detailSpawned = false; @override @@ -37,27 +39,38 @@ class TicketsExtension extends ClideExtension { Future activate(ClideExtensionContext ctx) async { _ctx = ctx; _selectionSub = ctx.messages.subscribe(publisher: id, channel: 'selection').listen(_onSelection); + _panelListener = () { + if (_detailSpawned && ctx.panels.activeTabIn(Slots.contextPanel) != 'tickets.detail') { + _despawnDetail(); + } + }; + ctx.panels.addListener(_panelListener!); } @override Future deactivate() async { _selectionSub?.cancel(); + if (_panelListener != null) _ctx?.panels.removeListener(_panelListener!); _despawnDetail(); } void _onSelection(Message msg) { final ctx = _ctx; if (ctx == null) return; - if (!_detailSpawned) { - ctx.panels.contribute(TabContribution( - id: 'tickets.detail', - slot: Slots.contextPanel, - title: 'Ticket', - priority: -60, - build: (_) => const TicketDetailView(), - )); - _detailSpawned = true; + final selectedId = msg.data['id'] as String?; + if (selectedId == null) return; + + if (_detailSpawned) { + _despawnDetail(); } + ctx.panels.contribute(TabContribution( + id: 'tickets.detail', + slot: Slots.contextPanel, + title: 'Ticket', + priority: -60, + build: (_) => TicketDetailView(initialId: selectedId), + )); + _detailSpawned = true; ctx.panels.activateTab(Slots.contextPanel, 'tickets.detail'); } diff --git a/lib/builtin/tickets/src/ticket_detail_view.dart b/lib/builtin/tickets/src/ticket_detail_view.dart index bb5c32b7..33345253 100644 --- a/lib/builtin/tickets/src/ticket_detail_view.dart +++ b/lib/builtin/tickets/src/ticket_detail_view.dart @@ -5,7 +5,8 @@ import 'package:clide/widgets/widgets.dart'; import 'package:flutter/widgets.dart'; class TicketDetailView extends StatefulWidget { - const TicketDetailView({super.key}); + const TicketDetailView({super.key, this.initialId}); + final String? initialId; @override State createState() => _TicketDetailViewState(); @@ -20,6 +21,9 @@ class _TicketDetailViewState extends State { if (_controller != null) return; final kernel = ClideKernel.of(context); _controller = TicketDetailController(ipc: kernel.ipc, messages: kernel.messages, panels: kernel.panels); + if (widget.initialId != null) { + _controller!.load(widget.initialId!); + } } @override