forked from core/mobile_nebula
Add a manual enrollment flow to support chromeos (#99)
This commit is contained in:
parent
17cc3477b7
commit
8fc3a40467
|
@ -109,21 +109,18 @@ class _AppState extends State<App> {
|
||||||
),
|
),
|
||||||
onGenerateRoute: (settings) {
|
onGenerateRoute: (settings) {
|
||||||
if (settings.name == '/') {
|
if (settings.name == '/') {
|
||||||
return platformPageRoute(context: context, builder: (context) => MainScreen(this.dnEnrolled.stream));
|
return platformPageRoute(context: context, builder: (context) => MainScreen(this.dnEnrolled));
|
||||||
}
|
}
|
||||||
|
|
||||||
final uri = Uri.parse(settings.name!);
|
final uri = Uri.parse(settings.name!);
|
||||||
if (uri.path == EnrollmentScreen.routeName) {
|
if (uri.path == EnrollmentScreen.routeName) {
|
||||||
String? code;
|
|
||||||
if (uri.hasFragment) {
|
|
||||||
final qp = Uri.splitQueryString(uri.fragment);
|
|
||||||
code = qp["code"];
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: maybe implement this as a dialog instead of a page, you can stack multiple enrollment screens which is annoying in dev
|
// TODO: maybe implement this as a dialog instead of a page, you can stack multiple enrollment screens which is annoying in dev
|
||||||
return platformPageRoute(
|
return platformPageRoute(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => EnrollmentScreen(code: code, stream: this.dnEnrolled),
|
builder: (context) => EnrollmentScreen(
|
||||||
|
code: EnrollmentScreen.parseCode(settings.name!),
|
||||||
|
stream: this.dnEnrolled
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ class _AboutScreenState extends State<AboutScreen> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 20),
|
padding: EdgeInsets.only(top: 20),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Copyright © 2020 Defined Networking, Inc',
|
'Copyright © 2022 Defined Networking, Inc',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
)),
|
)),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
import 'package:mobile_nebula/components/SimplePage.dart';
|
import 'package:mobile_nebula/components/SimplePage.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
@ -16,6 +16,22 @@ class EnrollmentScreen extends StatefulWidget {
|
||||||
|
|
||||||
static const routeName = '/v1/mobile-enrollment';
|
static const routeName = '/v1/mobile-enrollment';
|
||||||
|
|
||||||
|
// Attempts to find an enrollment code in the provided url. If one is not found then assume the input was
|
||||||
|
// an enrollment code. Primarily to support manual dn enrollment where the user can input a code or a url.
|
||||||
|
static String parseCode(String url) {
|
||||||
|
final uri = Uri.parse(url);
|
||||||
|
if (uri.path != EnrollmentScreen.routeName) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.hasFragment) {
|
||||||
|
final qp = Uri.splitQueryString(uri.fragment);
|
||||||
|
return qp["code"] ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
const EnrollmentScreen({super.key, this.code, this.stream, this.allowCodeEntry = false});
|
const EnrollmentScreen({super.key, this.code, this.stream, this.allowCodeEntry = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -138,20 +154,33 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SimplePage(title: Text('DN Enrollment'), child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)), alignment: alignment);
|
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
|
||||||
|
return SimplePage(
|
||||||
|
title: Text('Enroll with DN', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)),
|
||||||
|
alignment: alignment
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _codeEntry() {
|
Widget _codeEntry() {
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
Container(height: 20),
|
Padding(
|
||||||
PlatformTextField(controller: enrollInput),
|
padding: EdgeInsets.only(top: 20),
|
||||||
CupertinoButton(child: Text('Enroll'), onPressed: () {
|
child: PlatformTextField(
|
||||||
setState(() {
|
hintText: 'Enrollment code or link',
|
||||||
code = enrollInput.text;
|
controller: enrollInput
|
||||||
error = null;
|
)
|
||||||
_enroll();
|
),
|
||||||
});
|
PlatformTextButton(
|
||||||
}),
|
child: Text('Submit'),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
code = EnrollmentScreen.parseCode(enrollInput.text);
|
||||||
|
error = null;
|
||||||
|
_enroll();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ MAIH7gzreMGgrH/yR6rZpIHR3DxJ3E0aHtEI
|
||||||
class MainScreen extends StatefulWidget {
|
class MainScreen extends StatefulWidget {
|
||||||
const MainScreen(this.dnEnrollStream, {Key? key}) : super(key: key);
|
const MainScreen(this.dnEnrollStream, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
final Stream dnEnrollStream;
|
final StreamController dnEnrollStream;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MainScreenState createState() => _MainScreenState();
|
_MainScreenState createState() => _MainScreenState();
|
||||||
|
@ -82,7 +82,7 @@ class _MainScreenState extends State<MainScreen> {
|
||||||
void initState() {
|
void initState() {
|
||||||
_loadSites();
|
_loadSites();
|
||||||
|
|
||||||
widget.dnEnrollStream.listen((_) {
|
widget.dnEnrollStream.stream.listen((_) {
|
||||||
_loadSites();
|
_loadSites();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ class _MainScreenState extends State<MainScreen> {
|
||||||
PlatformIconButton(
|
PlatformIconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
icon: Icon(Icons.menu, size: 28.0),
|
icon: Icon(Icons.menu, size: 28.0),
|
||||||
onPressed: () => Utils.openPage(context, (_) => SettingsScreen()),
|
onPressed: () => Utils.openPage(context, (_) => SettingsScreen(widget.dnEnrollStream)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
bottomBar: debugSite,
|
bottomBar: debugSite,
|
||||||
|
|
|
@ -1,18 +1,24 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:mobile_nebula/components/SimplePage.dart';
|
import 'package:mobile_nebula/components/SimplePage.dart';
|
||||||
import 'package:mobile_nebula/components/config/ConfigItem.dart';
|
import 'package:mobile_nebula/components/config/ConfigItem.dart';
|
||||||
import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
|
import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
|
||||||
import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
||||||
|
import 'package:mobile_nebula/screens/EnrollmentScreen.dart';
|
||||||
import 'package:mobile_nebula/services/settings.dart';
|
import 'package:mobile_nebula/services/settings.dart';
|
||||||
import 'package:mobile_nebula/services/utils.dart';
|
import 'package:mobile_nebula/services/utils.dart';
|
||||||
|
|
||||||
import 'AboutScreen.dart';
|
import 'AboutScreen.dart';
|
||||||
|
|
||||||
class SettingsScreen extends StatefulWidget {
|
class SettingsScreen extends StatefulWidget {
|
||||||
|
final StreamController stream;
|
||||||
|
|
||||||
|
const SettingsScreen(this.stream, {super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SettingsScreenState createState() {
|
_SettingsScreenState createState() => _SettingsScreenState();
|
||||||
return _SettingsScreenState();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsScreenState extends State<SettingsScreen> {
|
class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
|
@ -79,6 +85,16 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
|
||||||
|
items.add(ConfigSection(children: [
|
||||||
|
ConfigPageItem(
|
||||||
|
label: Text('Enroll with DN'),
|
||||||
|
labelWidth: 200,
|
||||||
|
onPressed: () => Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true))
|
||||||
|
)
|
||||||
|
]));
|
||||||
|
|
||||||
items.add(ConfigSection(children: [
|
items.add(ConfigSection(children: [
|
||||||
ConfigPageItem(
|
ConfigPageItem(
|
||||||
label: Text('About'),
|
label: Text('About'),
|
||||||
|
|
Loading…
Reference in New Issue