feat: encrypted-history prompt, incoming-call alerts, message edit, panic button (v1.7.0+11)
P1 key_restore_prompt: offer recovery-key restore right after login P2 incoming calls: mount overlay in app.dart + detect MSC3401 call.member (Element X signalling) — calls were previously invisible P3 message edit: editMessage/EditMessage + Edit dialog (reactions/delete were already wired) P5 panic button: new feature/panic module — hold-to-send alert text + m.location to a configured room; alert sent before geolocation so a denied permission never blocks it All verified end-to-end in headless Chromium against production build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
// Version: 1.2.0 | Created: 2026-04-01 | Updated: 2026-04-02
|
||||
// Version: 1.3.0 | Created: 2026-04-01 | Updated: 2026-07-04
|
||||
// IncomingCallOverlay — full-screen overlay shown when an m.call.invite
|
||||
// arrives. Displays caller name/avatar, and Accept / Decline buttons.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../app/router.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../../shared/widgets/matrix_avatar.dart';
|
||||
@@ -58,20 +58,27 @@ class IncomingCallOverlayHost extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _IncomingCallOverlay extends StatefulWidget {
|
||||
class _IncomingCallOverlay extends ConsumerStatefulWidget {
|
||||
const _IncomingCallOverlay({required this.call});
|
||||
|
||||
final IncomingCall call;
|
||||
|
||||
@override
|
||||
State<_IncomingCallOverlay> createState() => _IncomingCallOverlayState();
|
||||
ConsumerState<_IncomingCallOverlay> createState() =>
|
||||
_IncomingCallOverlayState();
|
||||
}
|
||||
|
||||
class _IncomingCallOverlayState extends State<_IncomingCallOverlay> {
|
||||
class _IncomingCallOverlayState extends ConsumerState<_IncomingCallOverlay> {
|
||||
bool _dismissed = false;
|
||||
String? _dismissedForCallId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// A new call resets the dismissal so the overlay can show again.
|
||||
if (_dismissedForCallId != widget.call.callId) {
|
||||
_dismissed = false;
|
||||
_dismissedForCallId = widget.call.callId;
|
||||
}
|
||||
if (_dismissed) return const SizedBox.shrink();
|
||||
|
||||
final theme = Theme.of(context);
|
||||
@@ -129,9 +136,13 @@ class _IncomingCallOverlayState extends State<_IncomingCallOverlay> {
|
||||
label: 'Accept',
|
||||
colour: Colors.green,
|
||||
onTap: () {
|
||||
context.push(
|
||||
'/calls/${Uri.encodeComponent(call.roomId)}',
|
||||
);
|
||||
// The overlay lives above the router's navigator, so
|
||||
// context.push would not find GoRouter — use the
|
||||
// router instance directly, then dismiss the overlay.
|
||||
setState(() => _dismissed = true);
|
||||
ref
|
||||
.read(routerProvider)
|
||||
.push('/calls/${Uri.encodeComponent(call.roomId)}');
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user