Skip to content
Snippets Groups Projects
Commit 08a8d51f authored by Markin Igor's avatar Markin Igor
Browse files

Rework cancellation flows.

parent aa9f4562
No related branches found
No related tags found
1 merge request!2Resolve "Rework auth flow."
// app.dart
import '../config.dart';
import 'error-alert.dart';
import 'screens/splashscreen.dart';
import 'package:flutter/material.dart';
import 'screens/home.dart';
......@@ -6,6 +8,11 @@ import 'package:flutter/services.dart';
import 'dart:async';
import 'dart:developer';
import 'package:shared_preferences/shared_preferences.dart';
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';
......@@ -52,8 +59,6 @@ class App extends StatelessWidget {
navigateAfterFuture: initApplication,
)
);
}
}
......@@ -76,9 +81,59 @@ class _MainAppState extends State<MainApp> {
// Url of the app which invoked OAuth
String _invokerURL;
String _host = Config.appFlavor == Flavor.DEVELOPMENT ? Config.HOSTS[0] : Config.DEFAULT_APP_HOST;
Screen _currentScreen = Screen.App;
@override
initState() {
super.initState();
// 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);
log("Open $_invokerURL");
try {
await launch("$_invokerURL?token=$token&host=$_host");
} catch (e) {
log("Error launching url $_invokerURL");
}
}, 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) {
// Show only for android, because iOS will show the same alert as
// was for Auth request
openVereign();
} else {
setScreen(Screen.App);
}
} else {
showErrorAlert(context, Platform.isAndroid ? errorDetails : errorMessage, openVereign);
setScreen(Screen.App);
}
});
initUniLinks();
}
......@@ -89,37 +144,87 @@ class _MainAppState extends State<MainApp> {
}
Future<Null> initUniLinks() async {
updateAppMode(widget.initialUri);
handleLinkChange(widget.initialUri);
_sub = getUriLinksStream().listen((Uri uri) {
updateAppMode(uri);
handleLinkChange(uri);
}, onError: (err) {
log('got err: $err');
});
}
updateAppMode(Uri uri) {
handleLinkChange(Uri uri) {
if (uri?.path == "/authorize") {
setState(() {
_appMode = AppMode.Authorization;
_invokerURL = uri.queryParameters["invokerUrl"];
});
startOAuth();
} else {
setState(() {
_appMode = AppMode.Default;
});
openVereign();
}
}
setScreen(Screen screen) {
setState(() {
_currentScreen = screen;
});
}
openVereign() {
setScreen(Screen.Dashboard);
FlutterWebBrowser.openWebPage(url: _host, androidToolbarColor: Color(0xFFd51d32));
}
startOAuth() {
if (_currentScreen == Screen.OAuth) {
return;
}
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;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: Text("Vereign")),
body: Home(
mode: _appMode,
invokerURL: _invokerURL,
host: widget.initialHost
host: _host,
setHost: setHost,
openDashboardClick: openVereign,
authorizeClick: startOAuth,
)
);
}
......
import 'package:flutter/material.dart';
Future<void> showErrorAlert(context, errorString, callback) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Authorization error'),
content: Text(errorString),
actions: <Widget>[
FlatButton(
child: Text('Open Dashboard'),
onPressed: () async {
Navigator.of(context).pop();
callback();
},
),
],
);
},
);
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:flutter_app_auth_wrapper/flutter_app_auth_wrapper.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:developer';
import 'dart:convert';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
......@@ -13,46 +8,29 @@ import '../app.dart';
class Home extends StatefulWidget {
Home({
@required this.mode,
@required this.invokerURL,
@required this.host,
@required this.setHost,
@required this.authorizeClick,
@required this.openDashboardClick,
});
final AppMode mode;
final String invokerURL;
final String host;
final void Function(String) setHost;
final void Function() openDashboardClick;
final void Function() authorizeClick;
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String _host = Config.appFlavor == Flavor.DEVELOPMENT ? Config.HOSTS[0] : Config.DEFAULT_APP_HOST;
bool _hidden = true;
Screen _currentScreen = Screen.App;
@override
initState() {
super.initState();
// Set up initial host
if (widget.host != null) {
setState(() {
_host = widget.host;
});
}
setScreenByMode(widget.mode);
FlutterAppAuthWrapper.eventStream().listen((data) {
var token = json.decode(data.toString())["access_token"];
_showAlert(token);
setScreen(Screen.App);
}, onError: (error) {
log("Err $error");
setScreen(Screen.App);
});
Timer(
Duration(seconds: 3),
() {
......@@ -63,105 +41,6 @@ class _HomeState extends State<Home> {
);
}
setScreen(Screen screen) {
if (
_currentScreen == screen &&
screen != Screen.Dashboard // ATM we can not determine whether dashboard was closed or not, so we avoid this case
) {
return;
}
setState(() {
_currentScreen = screen;
});
if (_currentScreen == Screen.Dashboard) {
openVereign();
} else if (_currentScreen == Screen.OAuth) {
startOAuth();
}
}
Future<void> _showAlert(token) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Authorization success'),
actions: <Widget>[
FlatButton(
child: Text('Go back'),
onPressed: () async {
Navigator.of(context).pop();
log("Open ${widget.invokerURL}");
try {
await launch("${widget.invokerURL}?token=$token&host=$_host");
} catch (e) {
log("Error launching url ${widget.invokerURL}");
}
},
),
],
);
},
);
}
@override
void didUpdateWidget(Home oldWidget) {
// this method IS called when parent widget passes new "props"
// unlike React, this method IS called _before_ the build
// unlike React, this method ISN'T called after setState()
if (widget.host != oldWidget.host && widget.host != null) {
setState(() {
_host = widget.host;
});
}
if (widget.mode != oldWidget.mode) {
setScreenByMode(widget.mode);
}
super.didUpdateWidget(oldWidget);
}
setScreenByMode(AppMode mode) {
if (mode == AppMode.Authorization) {
setScreen(Screen.OAuth);
} else if (mode == AppMode.Default) {
setScreen(Screen.Dashboard);
}
}
openVereign() {
FlutterWebBrowser.openWebPage(url: _host, androidToolbarColor: Color(0xFFd51d32));
}
startOAuth() {
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"
],
),
);
}
@override
Widget build(BuildContext context) {
if (_hidden) {
......@@ -169,23 +48,20 @@ class _HomeState extends State<Home> {
}
var children = <Widget>[
_urlButton(context, "Open Dashboard", () => setScreen(Screen.Dashboard)),
_urlButton(context, "Open Dashboard", widget.openDashboardClick),
];
if (widget.mode == AppMode.Authorization) {
children.add(_urlButton(context, "Authorize with Vereign", () => setScreen(Screen.OAuth)));
children.add(_urlButton(context, "Authorize with Vereign", widget.authorizeClick));
}
if (Config.appFlavor == Flavor.DEVELOPMENT) {
children.add(
wrapInContainer(
DropdownButton<String>(
value: _host,
value: widget.host,
onChanged: (String newValue) async {
setState(() {
_host = newValue;
});
widget.setHost(newValue);
final prefs = await SharedPreferences.getInstance();
prefs.setString("host", newValue);
},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment