Skip to content
Snippets Groups Projects
app.dart 5.92 KiB
Newer Older
  • Learn to ignore specific revisions
  • igorwork's avatar
    igorwork committed
    // app.dart
    
    Markin Igor's avatar
    Markin Igor committed
    import '../config.dart';
    import 'error-alert.dart';
    
    Markin Igor's avatar
    Markin Igor committed
    import 'screens/splashscreen.dart';
    
    igorwork's avatar
    igorwork committed
    import 'package:flutter/material.dart';
    import 'screens/home.dart';
    
    import 'package:flutter/services.dart';
    import 'dart:async';
    import 'dart:developer';
    
    Markin Igor's avatar
    Markin Igor committed
    import 'package:shared_preferences/shared_preferences.dart';
    
    Markin Igor's avatar
    Markin Igor committed
    import 'package:flutter_web_browser/flutter_web_browser.dart';
    import 'dart:convert';
    import 'package:url_launcher/url_launcher.dart';
    import 'package:flutter_app_auth_wrapper/flutter_app_auth_wrapper.dart';
    import 'dart:io';
    
    
    import 'package:uni_links/uni_links.dart';
    
    
    enum AppMode {
      Default,
      Authorization,
    }
    
    enum Screen {
      App,
      OAuth,
      Dashboard
    }
    
    
    Markin Igor's avatar
    Markin Igor committed
    class App extends StatelessWidget {
    
    Markin Igor's avatar
    Markin Igor committed
      Future<Widget> initApplication() async {
        Uri initialUri;
    
        try {
          initialUri = await getInitialUri();
        } on PlatformException {
          initialUri = null;
        } on FormatException {
          initialUri = null;
        }
    
    
    Markin Igor's avatar
    Markin Igor committed
        final prefs = await SharedPreferences.getInstance();
        final host = prefs.getString('host');
    
        return new MainApp(initialUri: initialUri, initialHost: host);
    
      @override
    
    Markin Igor's avatar
    Markin Igor committed
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Vereign',
            theme: ThemeData(
                primaryColor: Color(0xFFd51d32),
                fontFamily: "Arial",
                textTheme: TextTheme(
                    button: TextStyle(color: Colors.white, fontSize: 18.0),
                    title: TextStyle(color: Colors.red))),
            home: new SplashScreen(
    
    Markin Igor's avatar
    Markin Igor committed
              navigateAfterFuture: initApplication,
    
    Markin Igor's avatar
    Markin Igor committed
            )
        );
      }
    }
    
    class MainApp extends StatefulWidget {
    
    Markin Igor's avatar
    Markin Igor committed
      MainApp({ @required this.initialUri, this.initialHost });
    
    Markin Igor's avatar
    Markin Igor committed
      final Uri initialUri;
    
    Markin Igor's avatar
    Markin Igor committed
      final String initialHost;
    
    Markin Igor's avatar
    Markin Igor committed
      @override
      _MainAppState createState() => _MainAppState();
    
    Markin Igor's avatar
    Markin Igor committed
    class _MainAppState extends State<MainApp> {
    
      StreamSubscription _sub;
    
    
      /// "Default" when you open app, "Authorization" when app initiated
      /// from third party app
      AppMode _appMode;
    
      // Url of the app which invoked OAuth
      String _invokerURL;
    
    
    Markin Igor's avatar
    Markin Igor committed
      String _host = Config.appFlavor == Flavor.DEVELOPMENT ? Config.HOSTS[0] : Config.DEFAULT_APP_HOST;
    
      Screen _currentScreen = Screen.App;
    
    
    Markin Igor's avatar
    Markin Igor committed
      bool _buttonsHidden = true;
    
    
      @override
      initState() {
        super.initState();
    
    Markin Igor's avatar
    Markin Igor committed
    
        // Set up app host
        if (widget.initialHost != null) {
          setState(() {
            _host = widget.initialHost;
          });
        }
    
        // Subscribe to authorization events
        FlutterAppAuthWrapper.eventStream().listen((data) async {
          var token = json.decode(data.toString())["access_token"];
          setScreen(Screen.App);
    
          try {
            await launch("$_invokerURL?token=$token&host=$_host");
          } catch (e) {
    
    Markin Igor's avatar
    Markin Igor committed
            showErrorAlert(context, 'Unable to open URL $_invokerURL', openVereign);
    
    Markin Igor's avatar
    Markin Igor committed
          revealButtons(1);
    
    Markin Igor's avatar
    Markin Igor committed
        }, onError: (error) {
          log("Err $error");
    
          String errorMessage = error.message;
          String errorDetails  = error.details;
    
          if (
            // Handle cancellation for Android
            errorDetails == '{"type":0,"code":1,"errorDescription":"User cancelled flow"}' ||
            // Handle cancellation for iOS
            errorMessage.toLowerCase().contains("the operation couldn")
          ) {
            if (Platform.isAndroid) {
    
    Markin Igor's avatar
    Markin Igor committed
              // Reveal after three seconds
              revealButtons(3);
    
              // Open only for android, because iOS will show the same alert as
    
    Markin Igor's avatar
    Markin Igor committed
              // was for Auth request
              openVereign();
            } else {
              setScreen(Screen.App);
    
    Markin Igor's avatar
    Markin Igor committed
              revealButtons(0);
    
    Markin Igor's avatar
    Markin Igor committed
            }
          } else {
            showErrorAlert(context, Platform.isAndroid ? errorDetails : errorMessage, openVereign);
            setScreen(Screen.App);
    
    Markin Igor's avatar
    Markin Igor committed
            revealButtons(0);
    
        initUniLinks();
    
    Markin Igor's avatar
    Markin Igor committed
    
        // Show buttons after timeout
        revealButtons(3);
    
      }
    
      @override
      dispose() {
        if (_sub != null) _sub.cancel();
        super.dispose();
      }
    
      Future<Null> initUniLinks() async {
    
    Markin Igor's avatar
    Markin Igor committed
        handleLinkChange(widget.initialUri);
    
    
        _sub = getUriLinksStream().listen((Uri uri) {
    
    Markin Igor's avatar
    Markin Igor committed
          handleLinkChange(uri);
    
        }, onError: (err) {
          log('got err: $err');
        });
      }
    
    
    Markin Igor's avatar
    Markin Igor committed
      revealButtons(delay) {
        Timer(
            Duration(seconds: delay),
                () {
              setState(() {
                _buttonsHidden = false;
              });
            }
        );
      }
    
    
    Markin Igor's avatar
    Markin Igor committed
      handleLinkChange(Uri uri) {
    
    igorwork's avatar
    igorwork committed
        if (uri?.path == "/authorize") {
    
          setState(() {
    
    igorwork's avatar
    igorwork committed
            _invokerURL = uri.queryParameters["invokerUrl"];
    
    Markin Igor's avatar
    Markin Igor committed
    
          startOAuth();
    
        } else {
          setState(() {
    
    Markin Igor's avatar
    Markin Igor committed
    
          openVereign();
    
    Markin Igor's avatar
    Markin Igor committed
      setScreen(Screen screen) {
        setState(() {
          _currentScreen = screen;
        });
      }
    
      openVereign() {
        setScreen(Screen.Dashboard);
    
        FlutterWebBrowser.openWebPage(url: _host, androidToolbarColor: Color(0xFFd51d32));
      }
    
      startOAuth() {
        if (_currentScreen == Screen.OAuth) {
          return;
        }
    
    
    Markin Igor's avatar
    Markin Igor committed
        // Hide buttons so they wont blink after we close or finish oauth
        setState(() {
          _buttonsHidden = true;
        });
    
    
    Markin Igor's avatar
    Markin Igor committed
        setScreen(Screen.OAuth);
    
        var params = Config.getOAuthParams(host: _host);
    
        FlutterAppAuthWrapper.startAuth(
          AuthConfig(
            clientId: params["clientId"],
            clientSecret: params["clientSecret"],
            redirectUrl: params["redirectUrl"],
            state: "login",
            prompt: "consent",
            endpoint: AuthEndpoint(
                auth: params["authEndpoint"], token: params["tokenEndpoint"]),
            scopes: [
              "user_account_status",
              "user_territory",
              "user_profile"
            ],
          ),
        );
      }
    
      setHost(String host) {
        setState(() {
          _host = host;
        });
      }
    
    
    igorwork's avatar
    igorwork committed
      @override
      Widget build(BuildContext context) {
    
    Markin Igor's avatar
    Markin Igor committed
        return new Scaffold(
          appBar: new AppBar(title: Text("Vereign")),
          body: Home(
            mode: _appMode,
    
    Markin Igor's avatar
    Markin Igor committed
            host: _host,
            setHost: setHost,
            openDashboardClick: openVereign,
            authorizeClick: startOAuth,
    
    Markin Igor's avatar
    Markin Igor committed
            buttonsHidden: _buttonsHidden
    
    Markin Igor's avatar
    Markin Igor committed
          )
    
    igorwork's avatar
    igorwork committed
        );
      }
    }