@@ -146,43 +146,79 @@ class _SettingsFormState extends State<SettingsForm> {
146146 _requestingKeys[service] = true ;
147147 });
148148
149+ bool cancelled = false ;
150+
149151 try {
150152 // Request and await key with browser opening
151153 final apiKey = await _keyRequestService.requestAndAwaitKey (
152154 serviceUrl: service,
153155 applicationName: 'Oncle Bob' ,
154- onPollStart: (browserUrl) {
156+ onPollStart: (browserUrl, requestId ) {
155157 // Copy browser URL to clipboard
156158 Clipboard .setData (ClipboardData (text: browserUrl));
157159
158160 // Show dialog with instructions
159161 if (mounted) {
160162 showDialog (
161163 context: context,
162- barrierDismissible: false ,
163- builder: (context) => AlertDialog (
164- title: const Text ('Approve Key Request' ),
165- content: Column (
166- mainAxisSize: MainAxisSize .min,
167- crossAxisAlignment: CrossAxisAlignment .start,
168- children: [
169- const Text ('Opening your browser to approve the API key request...' ),
170- const SizedBox (height: 16 ),
171- const Text ('If the browser doesn\' t open automatically, visit:' ),
172- const SizedBox (height: 8 ),
173- SelectableText (
174- browserUrl,
175- style: const TextStyle (
176- fontFamily: 'monospace' ,
177- fontSize: 12 ,
164+ barrierDismissible: true ,
165+ builder: (context) => PopScope (
166+ canPop: true ,
167+ onPopInvokedWithResult: (didPop, result) {
168+ if (didPop) {
169+ cancelled = true ;
170+ _keyRequestService.cancelRequest ();
171+ }
172+ },
173+ child: AlertDialog (
174+ title: const Text ('Approve Key Request' ),
175+ content: Column (
176+ mainAxisSize: MainAxisSize .min,
177+ crossAxisAlignment: CrossAxisAlignment .start,
178+ children: [
179+ const Text ('Opening your browser to approve the API key request...' ),
180+ if (requestId.isNotEmpty) ...[
181+ const SizedBox (height: 16 ),
182+ Row (
183+ children: [
184+ const Text ('Request ID: ' ),
185+ SelectableText (
186+ requestId,
187+ style: const TextStyle (
188+ fontFamily: 'monospace' ,
189+ fontWeight: FontWeight .bold,
190+ ),
191+ ),
192+ ],
193+ ),
194+ ],
195+ const SizedBox (height: 16 ),
196+ const Text ('If the browser doesn\' t open automatically, visit:' ),
197+ const SizedBox (height: 8 ),
198+ SelectableText (
199+ browserUrl,
200+ style: const TextStyle (
201+ fontFamily: 'monospace' ,
202+ fontSize: 12 ,
203+ ),
178204 ),
205+ const SizedBox (height: 8 ),
206+ const Text ('(URL copied to clipboard)' ),
207+ const SizedBox (height: 16 ),
208+ const Text ('Waiting for approval...' ),
209+ const SizedBox (height: 16 ),
210+ const Center (child: CircularProgressIndicator ()),
211+ ],
212+ ),
213+ actions: [
214+ TextButton (
215+ onPressed: () {
216+ cancelled = true ;
217+ _keyRequestService.cancelRequest ();
218+ Navigator .of (context).pop ();
219+ },
220+ child: const Text ('Cancel' ),
179221 ),
180- const SizedBox (height: 8 ),
181- const Text ('(URL copied to clipboard)' ),
182- const SizedBox (height: 16 ),
183- const Text ('Waiting for approval...' ),
184- const SizedBox (height: 16 ),
185- const Center (child: CircularProgressIndicator ()),
186222 ],
187223 ),
188224 ),
@@ -197,8 +233,16 @@ class _SettingsFormState extends State<SettingsForm> {
197233 },
198234 );
199235
236+ // Check if user cancelled while waiting
237+ if (cancelled) {
238+ setState (() {
239+ _requestingKeys.remove (service);
240+ });
241+ return ;
242+ }
243+
200244 // Close the waiting dialog
201- if (mounted) {
245+ if (mounted && Navigator . of (context). canPop () ) {
202246 Navigator .of (context).pop ();
203247 }
204248
@@ -227,8 +271,8 @@ class _SettingsFormState extends State<SettingsForm> {
227271 _requestingKeys.remove (service);
228272 });
229273
230- // Show error message
231- if (mounted) {
274+ // Show error message only if not cancelled
275+ if (mounted && ! cancelled ) {
232276 ScaffoldMessenger .of (context).showSnackBar (
233277 SnackBar (
234278 content: Text (e.toString ().replaceFirst ('Exception: ' , '' )),
0 commit comments