use subfolder for frontend/backend
This commit is contained in:
219
app/lib/main.dart
Normal file
219
app/lib/main.dart
Normal file
@ -0,0 +1,219 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:raid_manager/raid_page.dart';
|
||||
import 'package:sidebarx/sidebarx.dart';
|
||||
|
||||
void main() {
|
||||
runApp(SidebarXExampleApp());
|
||||
}
|
||||
|
||||
class SidebarXExampleApp extends StatelessWidget {
|
||||
SidebarXExampleApp({Key? key}) : super(key: key);
|
||||
|
||||
final _controller = SidebarXController(selectedIndex: 0, extended: true);
|
||||
final _key = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'SidebarX Example',
|
||||
theme: ThemeData(
|
||||
primaryColor: primaryColor,
|
||||
canvasColor: canvasColor,
|
||||
scaffoldBackgroundColor: scaffoldBackgroundColor,
|
||||
textTheme: const TextTheme(
|
||||
headlineSmall: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
headlineMedium: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
labelMedium: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w200
|
||||
)
|
||||
),
|
||||
),
|
||||
home: Builder(
|
||||
builder: (context) {
|
||||
final isSmallScreen = MediaQuery.of(context).size.width < 600;
|
||||
return Scaffold(
|
||||
key: _key,
|
||||
appBar: isSmallScreen
|
||||
? AppBar(
|
||||
backgroundColor: canvasColor,
|
||||
title: Text(_getTitleByIndex(_controller.selectedIndex)),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
// if (!Platform.isAndroid && !Platform.isIOS) {
|
||||
// _controller.setExtended(true);
|
||||
// }
|
||||
_key.currentState?.openDrawer();
|
||||
},
|
||||
icon: const Icon(Icons.menu),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
drawer: ExampleSidebarX(controller: _controller),
|
||||
body: Row(
|
||||
children: [
|
||||
if (!isSmallScreen) ExampleSidebarX(controller: _controller),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: _ScreensExample(
|
||||
controller: _controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExampleSidebarX extends StatelessWidget {
|
||||
const ExampleSidebarX({
|
||||
Key? key,
|
||||
required SidebarXController controller,
|
||||
}) : _controller = controller,
|
||||
super(key: key);
|
||||
|
||||
final SidebarXController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SidebarX(
|
||||
controller: _controller,
|
||||
theme: SidebarXTheme(
|
||||
margin: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: canvasColor,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
hoverColor: scaffoldBackgroundColor,
|
||||
textStyle: TextStyle(color: Colors.white.withOpacity(0.7)),
|
||||
selectedTextStyle: const TextStyle(color: Colors.white),
|
||||
itemTextPadding: const EdgeInsets.only(left: 30),
|
||||
selectedItemTextPadding: const EdgeInsets.only(left: 30),
|
||||
itemDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: canvasColor),
|
||||
),
|
||||
selectedItemDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: actionColor.withOpacity(0.37),
|
||||
),
|
||||
gradient: const LinearGradient(
|
||||
colors: [accentCanvasColor, canvasColor],
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.28),
|
||||
blurRadius: 30,
|
||||
)
|
||||
],
|
||||
),
|
||||
iconTheme: IconThemeData(
|
||||
color: Colors.white.withOpacity(0.7),
|
||||
size: 20,
|
||||
),
|
||||
selectedIconTheme: const IconThemeData(
|
||||
color: Colors.white,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
extendedTheme: const SidebarXTheme(
|
||||
width: 200,
|
||||
decoration: BoxDecoration(
|
||||
color: canvasColor,
|
||||
),
|
||||
),
|
||||
footerDivider: divider,
|
||||
headerBuilder: (context, extended) {
|
||||
return const SizedBox(
|
||||
height: 20
|
||||
);
|
||||
},
|
||||
items: const [
|
||||
SidebarXItem(
|
||||
icon: Icons.home,
|
||||
label: 'Raids',
|
||||
),
|
||||
SidebarXItem(
|
||||
icon: Icons.search,
|
||||
label: 'Disks',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ScreensExample extends StatelessWidget {
|
||||
const _ScreensExample({
|
||||
Key? key,
|
||||
required this.controller,
|
||||
}) : super(key: key);
|
||||
|
||||
final SidebarXController controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return AnimatedBuilder(
|
||||
animation: controller,
|
||||
builder: (context, child) {
|
||||
final pageTitle = _getTitleByIndex(controller.selectedIndex);
|
||||
switch (controller.selectedIndex) {
|
||||
case 0:
|
||||
return const RaidPage();
|
||||
case 1:
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
itemBuilder: (context, index) => Container(
|
||||
height: 100,
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.only(bottom: 10, right: 10, left: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).canvasColor,
|
||||
boxShadow: const [BoxShadow()],
|
||||
),
|
||||
),
|
||||
);
|
||||
default:
|
||||
return Text(
|
||||
pageTitle,
|
||||
style: theme.textTheme.headlineSmall,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _getTitleByIndex(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return 'Raids';
|
||||
case 1:
|
||||
return 'Disks';
|
||||
default:
|
||||
return 'Not found page';
|
||||
}
|
||||
}
|
||||
|
||||
const primaryColor = Color(0xFF685BFF);
|
||||
const canvasColor = Color(0xFF232323);
|
||||
const scaffoldBackgroundColor = Color(0xFF343434);
|
||||
const accentCanvasColor = Color(0xFF464646);
|
||||
const white = Colors.white;
|
||||
final actionColor = const Color(0xFF343434).withOpacity(0.6);
|
||||
final divider = Divider(color: white.withOpacity(0.3), height: 1);
|
15
app/lib/raid_info_page.dart
Normal file
15
app/lib/raid_info_page.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'types/md_raid_system.dart';
|
||||
|
||||
class RaidInfoPage extends StatelessWidget {
|
||||
const RaidInfoPage({Key? key, required this.raid}) : super(key: key);
|
||||
|
||||
final MdRaid raid;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(appBar: AppBar(title: Text(raid.name),),body: Text(raid.name));
|
||||
}
|
||||
}
|
60
app/lib/raid_page.dart
Normal file
60
app/lib/raid_page.dart
Normal file
@ -0,0 +1,60 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:raid_manager/raid_info_page.dart';
|
||||
import 'package:raid_manager/types/md_raid_system.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class RaidPage extends StatefulWidget {
|
||||
const RaidPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<RaidPage> createState() => _RaidPageState();
|
||||
}
|
||||
|
||||
class _RaidPageState extends State<RaidPage> {
|
||||
Future<MdRaidSystem> fetchRaids() async {
|
||||
final resp =
|
||||
await http.get(Uri.parse('http://127.0.0.1:8000/api/raiddevices'));
|
||||
return MdRaidSystem.fromJson(jsonDecode(resp.body));
|
||||
}
|
||||
|
||||
late final myFetch = fetchRaids();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: myFetch,
|
||||
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,
|
||||
),
|
||||
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 {
|
||||
return const Text("loading...");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
25
app/lib/types/md_raid_system.dart
Normal file
25
app/lib/types/md_raid_system.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
part 'md_raid_system.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class MdRaid {
|
||||
String name;
|
||||
bool faulty;
|
||||
String level;
|
||||
List<String> devices;
|
||||
|
||||
MdRaid(this.name, this.faulty, this.level, this.devices);
|
||||
factory MdRaid.fromJson(Map<String, dynamic> json) => _$MdRaidFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$MdRaidToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class MdRaidSystem {
|
||||
MdRaidSystem(this.supported_levels, this.raids);
|
||||
|
||||
List<String> supported_levels;
|
||||
List<MdRaid> raids;
|
||||
|
||||
factory MdRaidSystem.fromJson(Map<String, dynamic> json) => _$MdRaidSystemFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$MdRaidSystemToJson(this);
|
||||
}
|
36
app/lib/types/md_raid_system.g.dart
Normal file
36
app/lib/types/md_raid_system.g.dart
Normal file
@ -0,0 +1,36 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'md_raid_system.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
MdRaid _$MdRaidFromJson(Map<String, dynamic> json) => MdRaid(
|
||||
json['name'] as String,
|
||||
json['faulty'] as bool,
|
||||
json['level'] as String,
|
||||
(json['devices'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$MdRaidToJson(MdRaid instance) => <String, dynamic>{
|
||||
'name': instance.name,
|
||||
'faulty': instance.faulty,
|
||||
'level': instance.level,
|
||||
'devices': instance.devices,
|
||||
};
|
||||
|
||||
MdRaidSystem _$MdRaidSystemFromJson(Map<String, dynamic> json) => MdRaidSystem(
|
||||
(json['supported_levels'] as List<dynamic>)
|
||||
.map((e) => e as String)
|
||||
.toList(),
|
||||
(json['raids'] as List<dynamic>)
|
||||
.map((e) => MdRaid.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$MdRaidSystemToJson(MdRaidSystem instance) =>
|
||||
<String, dynamic>{
|
||||
'supported_levels': instance.supported_levels,
|
||||
'raids': instance.raids,
|
||||
};
|
Reference in New Issue
Block a user