import 'dart:io'; import 'package:desktopapp/classes/routes.dart'; import 'package:desktopapp/utils/logger.dart'; import 'package:desktopapp/utils/requests.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher.dart'; class Step3 extends StatelessWidget { const Step3({Key? key, required this.onPrevious}) : super(key: key); final VoidCallback onPrevious; Widget buildContent(BuildContext context, SharedPreferences prefs) { return Column(children: [ const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: Text('Étape 3: Autorisation de l\'application', style: TextStyle(fontSize: 20)), ), const Text( 'Pour terminer la configuration, il reste plus qu\'à se connecter à Streamlabs pour autoriser l\'application à créer des alertes.'), const SizedBox(height: 10), TextButton( onPressed: () async { waitAuthorization(context, prefs); var clientId = prefs.getString('client_id'); await Future.delayed(const Duration(seconds: 1)); launch( 'https://streamlabs.com/api/v1.0/authorize?redirect_uri=http://localhost:1234/&client_id=$clientId&response_type=code&scope=alerts.create'); }, child: const Text('Cliquez ici pour vous connecter à Streamlabs')), ]); } Future waitAuthorizationCallback(SharedPreferences prefs) async { var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 1234); Logger.log(LoggerType.info, this, 'Server started at ${server.address.address}:${server.port}'); var request = await server.first; var uri = Uri.dataFromString(request.requestedUri.toString()); var query = uri.queryParameters; var code = query['code']; if (code != null) { prefs.setString('code', code); request.response ..headers.contentType = ContentType.text ..write('You can close tab now') ..close(); } else { request.response ..headers.contentType = ContentType.text ..write('Internal error') ..close(); } return code; } Future waitAuthorization( BuildContext context, SharedPreferences prefs) async { var code = await waitAuthorizationCallback(prefs); if (code != null) { if (prefs.containsKey('credentials')) { showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Info'), content: const Text( 'Connexion réussi. Appuyez sur OK pour acceder à l\'application.'), actions: [ TextButton( onPressed: () { Navigator.pop(context); Navigator.of(context) .pushReplacementNamed(Routes.home.path); }, child: const Text('OK')) ], )); } else { if (await Requests.authorize(code, AuthentificationType.code)) { showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Info'), content: const Text( 'Connexion réussi. Appuyez sur OK pour acceder à l\'application.'), actions: [ TextButton( onPressed: () { Navigator.pop(context); Navigator.of(context) .pushReplacementNamed(Routes.home.path); }, child: const Text('OK')) ], )); } else { showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Erreur'), content: const Text('Impossible de se connecter.'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('OK')) ], )); } } } else { Logger.log(LoggerType.error, this, 'Authorization error : impossible to get code'); showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Erreur'), content: const Text('Impossible de se connecter.'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('OK')) ], )); } } @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: FutureBuilder( future: SharedPreferences.getInstance(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { final prefs = snapshot.data!; return buildContent(context, prefs); } else { return const Center(child: CircularProgressIndicator()); } })), Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton( onPressed: onPrevious, child: const Text('Étape précédente')) ], ), ) ], ); } }