| .. | .. |
|---|
| 20 | 20 | import '../services/audio_service.dart'; |
|---|
| 21 | 21 | import '../services/message_store.dart'; |
|---|
| 22 | 22 | import '../services/mqtt_service.dart'; |
|---|
| 23 | +import '../services/push_service.dart'; |
|---|
| 23 | 24 | import '../theme/app_theme.dart'; |
|---|
| 24 | 25 | import '../widgets/command_bar.dart'; |
|---|
| 25 | 26 | import '../widgets/input_bar.dart'; |
|---|
| .. | .. |
|---|
| 51 | 52 | class _ChatScreenState extends ConsumerState<ChatScreen> |
|---|
| 52 | 53 | with WidgetsBindingObserver { |
|---|
| 53 | 54 | MqttService? _ws; |
|---|
| 55 | + PushService? _push; |
|---|
| 54 | 56 | final TextEditingController _textController = TextEditingController(); |
|---|
| 55 | 57 | final ScrollController _scrollController = ScrollController(); |
|---|
| 56 | 58 | final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); |
|---|
| .. | .. |
|---|
| 185 | 187 | final activeId = ref.read(activeSessionIdProvider); |
|---|
| 186 | 188 | _sendCommand('sync', activeId != null ? {'activeSessionId': activeId} : null); |
|---|
| 187 | 189 | // catch_up is sent after sessions arrive (in _handleSessions) |
|---|
| 190 | + |
|---|
| 191 | + // Re-register APNs token after reconnect so daemon always has a fresh token |
|---|
| 192 | + _push?.onMqttConnected(); |
|---|
| 188 | 193 | }; |
|---|
| 189 | 194 | _ws!.onResume = () { |
|---|
| 190 | 195 | // App came back from background with connection still alive. |
|---|
| .. | .. |
|---|
| 206 | 211 | ); |
|---|
| 207 | 212 | |
|---|
| 208 | 213 | await _ws!.connect(); |
|---|
| 214 | + |
|---|
| 215 | + // Initialize push notifications after MQTT is set up so token can be |
|---|
| 216 | + // sent immediately if already connected. |
|---|
| 217 | + _push = PushService(mqttService: _ws!); |
|---|
| 218 | + _push!.onNotificationTap = (data) { |
|---|
| 219 | + // If notification carried a sessionId, switch to it |
|---|
| 220 | + final sessionId = data['sessionId'] as String?; |
|---|
| 221 | + if (sessionId != null && mounted) { |
|---|
| 222 | + ref.read(activeSessionIdProvider.notifier).state = sessionId; |
|---|
| 223 | + ref.read(messagesProvider.notifier).switchSession(sessionId); |
|---|
| 224 | + } |
|---|
| 225 | + }; |
|---|
| 226 | + await _push!.initialize(); |
|---|
| 209 | 227 | } |
|---|
| 210 | 228 | |
|---|
| 211 | 229 | void _handleMessage(Map<String, dynamic> msg) { |
|---|