| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | import 'dart:io'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:image/image.dart' as img; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'package:image_picker/image_picker.dart'; | 
					
						
							|  |  |  | import 'package:qr_code_scanner/qr_code_scanner.dart'; | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | import 'package:zxing2/qrcode.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-24 23:33:00 +08:00
										 |  |  | import '../../common.dart'; | 
					
						
							| 
									
										
										
										
											2024-02-25 13:29:06 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-21 15:41:07 +09:00
										 |  |  | import '../widgets/dialog.dart'; | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ScanPage extends StatefulWidget { | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-12-21 15:41:07 +09:00
										 |  |  |   State<ScanPage> createState() => _ScanPageState(); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _ScanPageState extends State<ScanPage> { | 
					
						
							|  |  |  |   QRViewController? controller; | 
					
						
							|  |  |  |   final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |   StreamSubscription? scanSubscription; | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void reassemble() { | 
					
						
							|  |  |  |     super.reassemble(); | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |     if (isAndroid && controller != null) { | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |       controller!.pauseCamera(); | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |     } else if (controller != null) { | 
					
						
							|  |  |  |       controller!.resumeCamera(); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Scaffold( | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |       appBar: AppBar( | 
					
						
							|  |  |  |         title: const Text('Scan QR'), | 
					
						
							|  |  |  |         actions: [ | 
					
						
							|  |  |  |           _buildImagePickerButton(), | 
					
						
							|  |  |  |           _buildFlashToggleButton(), | 
					
						
							|  |  |  |           _buildCameraSwitchButton(), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |       body: _buildQrView(context), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildQrView(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |     var scanArea = MediaQuery.of(context).size.width < 400 || | 
					
						
							|  |  |  |             MediaQuery.of(context).size.height < 400 | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |         ? 150.0 | 
					
						
							|  |  |  |         : 300.0; | 
					
						
							|  |  |  |     return QRView( | 
					
						
							|  |  |  |       key: qrKey, | 
					
						
							|  |  |  |       onQRViewCreated: _onQRViewCreated, | 
					
						
							|  |  |  |       overlay: QrScannerOverlayShape( | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |         borderColor: Colors.red, | 
					
						
							|  |  |  |         borderRadius: 10, | 
					
						
							|  |  |  |         borderLength: 30, | 
					
						
							|  |  |  |         borderWidth: 10, | 
					
						
							|  |  |  |         cutOutSize: scanArea, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |       onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p), | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _onQRViewCreated(QRViewController controller) { | 
					
						
							|  |  |  |     setState(() { | 
					
						
							|  |  |  |       this.controller = controller; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |     scanSubscription = controller.scannedDataStream.listen((scanData) { | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |       if (scanData.code != null) { | 
					
						
							|  |  |  |         showServerSettingFromQr(scanData.code!); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) { | 
					
						
							|  |  |  |     if (!p) { | 
					
						
							| 
									
										
										
										
											2022-08-15 14:39:31 +08:00
										 |  |  |       showToast('No permission'); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |   Future<void> _pickImage() async { | 
					
						
							|  |  |  |     final ImagePicker picker = ImagePicker(); | 
					
						
							|  |  |  |     final XFile? file = await picker.pickImage(source: ImageSource.gallery); | 
					
						
							|  |  |  |     if (file != null) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         var image = img.decodeImage(await File(file.path).readAsBytes())!; | 
					
						
							|  |  |  |         LuminanceSource source = RGBLuminanceSource( | 
					
						
							|  |  |  |           image.width, | 
					
						
							|  |  |  |           image.height, | 
					
						
							|  |  |  |           image.getBytes(order: img.ChannelOrder.abgr).buffer.asInt32List(), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         var bitmap = BinaryBitmap(HybridBinarizer(source)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var reader = QRCodeReader(); | 
					
						
							|  |  |  |         var result = reader.decode(bitmap); | 
					
						
							|  |  |  |         if (result.text.startsWith(bind.mainUriPrefixSync())) { | 
					
						
							|  |  |  |           handleUriLink(uriString: result.text); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           showServerSettingFromQr(result.text); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         showToast('No QR code found'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildImagePickerButton() { | 
					
						
							|  |  |  |     return IconButton( | 
					
						
							|  |  |  |       color: Colors.white, | 
					
						
							|  |  |  |       icon: Icon(Icons.image_search), | 
					
						
							|  |  |  |       iconSize: 32.0, | 
					
						
							|  |  |  |       onPressed: _pickImage, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildFlashToggleButton() { | 
					
						
							|  |  |  |     return IconButton( | 
					
						
							|  |  |  |       color: Colors.yellow, | 
					
						
							|  |  |  |       icon: Icon(Icons.flash_on), | 
					
						
							|  |  |  |       iconSize: 32.0, | 
					
						
							|  |  |  |       onPressed: () async { | 
					
						
							|  |  |  |         await controller?.toggleFlash(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildCameraSwitchButton() { | 
					
						
							|  |  |  |     return IconButton( | 
					
						
							|  |  |  |       color: Colors.white, | 
					
						
							|  |  |  |       icon: Icon(Icons.switch_camera), | 
					
						
							|  |  |  |       iconSize: 32.0, | 
					
						
							|  |  |  |       onPressed: () async { | 
					
						
							|  |  |  |         await controller?.flipCamera(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							| 
									
										
										
										
											2024-09-25 23:34:12 -03:00
										 |  |  |     scanSubscription?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |     controller?.dispose(); | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void showServerSettingFromQr(String data) async { | 
					
						
							| 
									
										
										
										
											2022-08-16 21:27:21 +08:00
										 |  |  |     closeConnection(); | 
					
						
							| 
									
										
										
										
											2022-04-18 17:01:45 +08:00
										 |  |  |     await controller?.pauseCamera(); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |     if (!data.startsWith('config=')) { | 
					
						
							| 
									
										
										
										
											2022-08-15 14:39:31 +08:00
										 |  |  |       showToast('Invalid QR code'); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2022-12-21 15:41:07 +09:00
										 |  |  |       final sc = ServerConfig.decode(data.substring(7)); | 
					
						
							| 
									
										
										
										
											2022-04-18 17:01:45 +08:00
										 |  |  |       Timer(Duration(milliseconds: 60), () { | 
					
						
							| 
									
										
										
										
											2022-12-21 16:24:01 +09:00
										 |  |  |         showServerSettingsWithValue(sc, gFFI.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-04-18 17:01:45 +08:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2022-08-15 14:39:31 +08:00
										 |  |  |       showToast('Invalid QR code'); | 
					
						
							| 
									
										
										
										
											2022-04-15 17:50:15 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |