add breadcrumbs and allow clicking on disks
This commit is contained in:
parent
36523a1203
commit
ceeae0523e
127
app/lib/breadcrumb_page.dart
Normal file
127
app/lib/breadcrumb_page.dart
Normal file
@ -0,0 +1,127 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_breadcrumb/flutter_breadcrumb.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class _BreadCrumbNode {
|
||||
String name;
|
||||
Widget widget;
|
||||
_BreadCrumbNode? next;
|
||||
|
||||
_BreadCrumbNode(this.name, this.widget);
|
||||
}
|
||||
|
||||
class BreadCrumbController extends ChangeNotifier {
|
||||
final Widget defaultRoute;
|
||||
final String rootName;
|
||||
|
||||
late _BreadCrumbNode _rootPage = _BreadCrumbNode(rootName, defaultRoute);
|
||||
late Widget _currentpage = _rootPage.widget;
|
||||
|
||||
void pushPage(Widget widget, String name) {
|
||||
_last(_rootPage).next = _BreadCrumbNode(name, widget);
|
||||
_currentpage = widget;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void switchPage(String name) {
|
||||
final pageNode = _findPage(name, _rootPage);
|
||||
if (pageNode != null) {
|
||||
_currentpage = pageNode.widget;
|
||||
// hope for garbage collector to free the floating items (;
|
||||
pageNode.next = null;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<String> getNames() {
|
||||
return _genNameList(_rootPage);
|
||||
}
|
||||
|
||||
Widget getCurrentPage() {
|
||||
return _currentpage;
|
||||
}
|
||||
|
||||
_BreadCrumbNode _last(_BreadCrumbNode node) {
|
||||
if (node.next != null) {
|
||||
return _last(node.next!);
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
_BreadCrumbNode? _findPage(String name, _BreadCrumbNode node) {
|
||||
if (node.name == name) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (node.next != null) {
|
||||
return _findPage(name, node.next!);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> _genNameList(_BreadCrumbNode node) {
|
||||
if (node.next != null) {
|
||||
return _genNameList(node.next!)..insert(0, node.name);
|
||||
} else {
|
||||
return [node.name];
|
||||
}
|
||||
}
|
||||
|
||||
BreadCrumbController(this.defaultRoute, this.rootName);
|
||||
}
|
||||
|
||||
class BreadCrumbPage extends StatefulWidget {
|
||||
const BreadCrumbPage(
|
||||
{Key? key, required this.mainPage, required this.rootName})
|
||||
: super(key: key);
|
||||
|
||||
final Widget mainPage;
|
||||
final String rootName;
|
||||
|
||||
@override
|
||||
State<BreadCrumbPage> createState() => _BreadCrumbPageState();
|
||||
}
|
||||
|
||||
class _BreadCrumbPageState extends State<BreadCrumbPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider<BreadCrumbController>(
|
||||
create: (BuildContext context) =>
|
||||
BreadCrumbController(widget.mainPage, widget.rootName),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 12, top: 8, bottom: 8),
|
||||
child: Consumer<BreadCrumbController>(
|
||||
builder: (_, controller, __) => BreadCrumb(
|
||||
items: controller
|
||||
.getNames()
|
||||
.map((e) => BreadCrumbItem(
|
||||
padding: const EdgeInsets.all(2),
|
||||
content: Text(e,
|
||||
style: Theme.of(context).textTheme.labelMedium),
|
||||
onTap: () {
|
||||
controller.switchPage(e);
|
||||
},
|
||||
))
|
||||
.toList(growable: false),
|
||||
divider: Icon(
|
||||
Icons.chevron_right,
|
||||
color: Theme.of(context).textTheme.labelMedium?.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(color: Colors.white.withOpacity(0.3), height: 1),
|
||||
Consumer<BreadCrumbController>(
|
||||
builder: (_, value, __) => value.getCurrentPage(),
|
||||
)
|
||||
// currentPage
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:raid_manager/api/request.dart';
|
||||
import 'package:raid_manager/breadcrumb_page.dart';
|
||||
import 'package:raid_manager/types/disk.dart';
|
||||
import 'package:raid_manager/utils/file_formatter.dart';
|
||||
|
||||
@ -12,42 +14,67 @@ class DiskPage extends StatefulWidget {
|
||||
|
||||
class _DiskPageState extends State<DiskPage> {
|
||||
Future<List<Disk>> fetchDisks() async {
|
||||
return (await getJson('/api/disks') as List)
|
||||
return ((await getJson('/api/disks')) as List)
|
||||
.map((e) => Disk.fromJson(e))
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
late final myFetch = fetchDisks();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
myFetch = fetchDisks();
|
||||
}
|
||||
|
||||
late Future<List<Disk>> myFetch;
|
||||
|
||||
Widget _buildMainPage() {
|
||||
return Expanded(
|
||||
child: FutureBuilder(
|
||||
future: myFetch,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState != ConnectionState.done) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
if (snapshot.hasError) {
|
||||
print(snapshot.error);
|
||||
return const Text("errored");
|
||||
} else if (snapshot.hasData) {
|
||||
final data = snapshot.data!;
|
||||
return ListView.builder(
|
||||
itemCount: data.length,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemBuilder: (context, idx) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
data[idx].name,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
subtitle: Text(
|
||||
data[idx].size.readableFileSize(),
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
onTap: () {
|
||||
Provider.of<BreadCrumbController>(context, listen: false)
|
||||
.pushPage(
|
||||
const Text("Mysupercool page"), data[idx].name);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return const Text("loading...");
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: myFetch,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final data = snapshot.data!;
|
||||
return ListView.builder(
|
||||
itemCount: data.length,
|
||||
itemBuilder: (context, idx) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
data[idx].name,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
subtitle: Text(
|
||||
data[idx].size.readableFileSize(),
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
onTap: () {},
|
||||
);
|
||||
},
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text("errored");
|
||||
} else {
|
||||
return const Text("loading...");
|
||||
}
|
||||
},
|
||||
return BreadCrumbPage(
|
||||
mainPage: _buildMainPage(),
|
||||
rootName: "Disks",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import 'package:raid_manager/raid_page.dart';
|
||||
import 'package:sidebarx/sidebarx.dart';
|
||||
|
||||
void main() {
|
||||
print("starting");
|
||||
runApp(SidebarXExampleApp());
|
||||
}
|
||||
|
||||
|
@ -24,27 +24,44 @@ class _RaidPageState extends State<RaidPage> {
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final data = snapshot.data!;
|
||||
return ListView.builder(
|
||||
itemCount: data.raids.length,
|
||||
itemBuilder: (context, idx) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
data.raids[idx].name,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
|
||||
if (data.raids.isEmpty) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.warning_amber_rounded,
|
||||
size: 42, color: Colors.white.withOpacity(.6)),
|
||||
const SizedBox(
|
||||
height: 7,
|
||||
),
|
||||
subtitle: Text(
|
||||
"${data.raids[idx].level} - ${data.raids[idx].faulty ? "errored" : "active sync"}",
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RaidInfoPage(raid: data.raids[idx])));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
Text("No Raid available",
|
||||
style: Theme.of(context).textTheme.headlineMedium)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return ListView.builder(
|
||||
itemCount: data.raids.length,
|
||||
itemBuilder: (context, idx) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
data.raids[idx].name,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
subtitle: Text(
|
||||
"${data.raids[idx].level} - ${data.raids[idx].faulty ? "errored" : "active sync"}",
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) =>
|
||||
RaidInfoPage(raid: data.raids[idx])));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text("errored");
|
||||
} else {
|
||||
|
@ -181,6 +181,13 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_breadcrumb:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_breadcrumb
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -305,6 +312,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -319,6 +333,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -326,6 +347,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
provider:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.4"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -52,6 +52,8 @@ dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
||||
build_runner:
|
||||
json_serializable:
|
||||
flutter_breadcrumb: ^1.0.1
|
||||
provider:
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
Loading…
Reference in New Issue
Block a user