diff --git a/android/app/src/main/kotlin/fr/astrolabe/astronote_app/MainActivity.kt b/android/app/src/main/kotlin/fr/astrolabe/astronote_app/MainActivity.kt index 706262d..77f35ec 100644 --- a/android/app/src/main/kotlin/fr/astrolabe/astronote_app/MainActivity.kt +++ b/android/app/src/main/kotlin/fr/astrolabe/astronote_app/MainActivity.kt @@ -1,6 +1,69 @@ package fr.astrolabe.astronote_app +import android.content.BroadcastReceiver +import android.os.Bundle +import android.content.Context +import android.content.Intent +import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.EventChannel.EventSink +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugins.GeneratedPluginRegistrant -class MainActivity: FlutterActivity() { +class MainActivity : FlutterActivity() { + + private val CHANNEL = "https://demo.endi.coop" + private val EVENTS = "https://demo.endi.coop/login?nextpage=%2F" + private var startString: String? = null + private var linksReceiver: BroadcastReceiver? = null + + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine) + + MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result -> + if (call.method == "initialLink") { + if (startString != null) { + result.success(startString) + } + } + } + + EventChannel(flutterEngine.dartExecutor, EVENTS).setStreamHandler( + object : EventChannel.StreamHandler { + override fun onListen(args: Any?, events: EventSink) { + linksReceiver = createChangeReceiver(events) + } + + override fun onCancel(args: Any?) { + linksReceiver = null + } + } + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val intent = getIntent() + startString = intent.data?.toString() + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + if (intent.action === Intent.ACTION_VIEW) { + linksReceiver?.onReceive(this.applicationContext, intent) + } + } + + fun createChangeReceiver(events: EventSink): BroadcastReceiver? { + return object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { // assuming intent.getAction() is Intent.ACTION_VIEW + val dataString = intent.dataString + ?: events.error("UNAVAILABLE", "Link unavailable", null) + events.success(dataString) + } + } + } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 5bc5275..5b7006a 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -41,5 +41,9 @@ UIViewControllerBasedStatusBarAppearance + com.apple.developer.associated-domains + + applinks:demo.endi.coop + diff --git a/lib/bloc.dart b/lib/bloc.dart new file mode 100644 index 0000000..211aa1d --- /dev/null +++ b/lib/bloc.dart @@ -0,0 +1,48 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +abstract class Bloc { + void dispose(); +} + +class DeepLinkBloc extends Bloc { + //Event Channel creation + static const stream = + const EventChannel('https://demo.endi.coop/login?nextpage=%2F'); + + //Method channel creation + static const platform = const MethodChannel('https://demo.endi.coop'); + + StreamController _stateController = StreamController(); + + Stream get state => _stateController.stream; + + Sink get stateSink => _stateController.sink; + + //Adding the listener into contructor + DeepLinkBloc() { + //Checking application start by deep link + startUri().then(_onRedirected); + //Checking broadcast stream, if deep link was clicked in opened appication + stream.receiveBroadcastStream().listen((d) => _onRedirected(d)); + } + + _onRedirected(String uri) { + // Throw deep link URI into the BloC's stream + stateSink.add(uri); + } + + @override + void dispose() { + _stateController.close(); + } + + Future startUri() async { + try { + return platform.invokeMethod('initialLink'); + } on PlatformException catch (e) { + return "Failed to Invoke: '${e.message}'."; + } + } +} diff --git a/lib/views/HomeLog.dart b/lib/endi.dart similarity index 56% rename from lib/views/HomeLog.dart rename to lib/endi.dart index d3bc8c9..3f73abc 100644 --- a/lib/views/HomeLog.dart +++ b/lib/endi.dart @@ -1,48 +1,57 @@ -import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'bloc.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flushbar/flushbar.dart'; -class HomeLog extends StatefulWidget { +class EndiLog extends StatefulWidget { @override - _HomeLogState createState() => _HomeLogState(); + _EndiLogState createState() => _EndiLogState(); } -class _HomeLogState extends State { +class _EndiLogState extends State { TextStyle style = TextStyle(fontFamily: 'Varela Round', fontSize: 20.0); - final GlobalKey _globalKey = GlobalKey(); @override Widget build(BuildContext context) { - return Scaffold( - key: _globalKey, - body: SingleChildScrollView( - child: Container( - height: MediaQuery.of(context).size.height, - color: Colors.white, - child: Padding( - padding: EdgeInsets.all(50), - child: Column( - children: [ - SizedBox(height: 40), - _logoApp(), - _titleApp(), - SizedBox(height: 90), - _emailField(), - SizedBox(height: 30), - _passwordField(), - SizedBox(height: 50), - _logButton(), - SizedBox(height: 70), - _enDIUrl(), - SizedBox(height: 10), - _astrolabeUrl() - ], - ), - ), - ), - ), - ); + DeepLinkBloc _bloc = Provider.of(context); + return StreamBuilder( + stream: _bloc.state, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Container( + child: Center(child: Text('No deep link was used '))); + } else { + return SingleChildScrollView( + child: Container( + height: MediaQuery.of(context).size.height, + color: Colors.white, + child: Padding( + padding: EdgeInsets.all(50), + child: Column( + children: [ +// SizedBox(height: 40), + _logoApp(), + _titleApp(), + SizedBox(height: 80), + _emailField(), + SizedBox(height: 30), + _passwordField(), + SizedBox(height: 50), + _logButton(), + SizedBox(height: 70), + _enDIUrl(), + SizedBox(height: 5), + _astrolabeUrl() + ], + ), + ), + ), + ); + } + }); } + Widget _logoApp() { return SizedBox( height: 100.0, @@ -67,7 +76,7 @@ class _HomeLogState extends State { contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0), labelText: "E-mail", border: - OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))), + OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))), ); } @@ -79,7 +88,7 @@ class _HomeLogState extends State { contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0), labelText: "Mot de passe", border: - OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))), + OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))), ); } @@ -99,18 +108,22 @@ class _HomeLogState extends State { )); } + void showErrorFlushbar(BuildContext context) { + Flushbar( + message: "Impossible d'ouvrir le lien", + backgroundColor: Colors.red[300], + duration: Duration(seconds: 3), + // Show it with a cascading operator + )..show(context); + } + void _launchLinkEnDI() async { const url = "https://endi.coop"; if (await canLaunch(url)) { await launch(url); } else { - final snack = SnackBar( - content: Text("Impossible de lancer le lien"), - duration: Duration(seconds: 4), - backgroundColor: Colors.red[300], - ); - _globalKey.currentState.showSnackBar(snack); + showErrorFlushbar(context); } } @@ -120,12 +133,7 @@ class _HomeLogState extends State { if (await canLaunch(url)) { await launch(url); } else { - final snack = SnackBar( - content: Text("Impossible de lancer le lien"), - duration: Duration(seconds: 4), - backgroundColor: Colors.red[300], - ); - _globalKey.currentState.showSnackBar(snack); + showErrorFlushbar(context); } } @@ -154,5 +162,4 @@ class _HomeLogState extends State { ), ); } - } diff --git a/lib/main.dart b/lib/main.dart index 3f53b7b..d572967 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; -import 'views/HomeLog.dart'; +import 'bloc.dart'; +import 'package:provider/provider.dart'; +import 'endi.dart'; void main() => runApp(MyApp()); @@ -7,11 +9,14 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { + DeepLinkBloc _bloc = DeepLinkBloc(); + return MaterialApp( - home: HomeLog(), - debugShowCheckedModeBanner: false, - ); + debugShowCheckedModeBanner: false, + home: Scaffold( + body: Provider( + create: (context) => _bloc, + dispose: (context, bloc) => bloc.dispose(), + child: EndiLog()))); } } - - diff --git a/pubspec.lock b/pubspec.lock index 2c689ae..9176334 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -64,13 +64,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.3" - email_validator: + flushbar: dependency: "direct main" description: - name: email_validator + name: flushbar url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.10.4" flutter: dependency: "direct main" description: flutter @@ -267,5 +267,5 @@ packages: source: hosted version: "3.6.1" sdks: - dart: ">=2.7.0 <3.0.0" + dart: ">=2.7.2 <3.0.0" flutter: ">=1.16.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2218d8e..a08acdd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: flutter: sdk: flutter provider: ^4.3.1 - email_validator: '^1.0.0' + flushbar: ^1.10.4 url_launcher: ^5.5.0 # The following adds the Cupertino Icons font to your application.