Add a manual enrollment flow to support chromeos (#99)

This commit is contained in:
Nate Brown 2022-11-22 10:12:38 -06:00 committed by GitHub
parent 17cc3477b7
commit 8fc3a40467
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 26 deletions

View File

@ -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
),
); );
} }

View File

@ -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,
)), )),
]), ]),

View File

@ -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(
hintText: 'Enrollment code or link',
controller: enrollInput
)
),
PlatformTextButton(
child: Text('Submit'),
onPressed: () {
setState(() { setState(() {
code = enrollInput.text; code = EnrollmentScreen.parseCode(enrollInput.text);
error = null; error = null;
_enroll(); _enroll();
}); });
}), },
)
]); ]);
} }
} }

View File

@ -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,

View File

@ -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'),