add providers per page
show only 10 packages new page for all packages
This commit is contained in:
parent
920e11abcc
commit
bb34e56be0
@ -2,8 +2,9 @@ import '../models/package.dart';
|
|||||||
import 'api_client.dart';
|
import 'api_client.dart';
|
||||||
|
|
||||||
extension PackagesAPI on ApiClient {
|
extension PackagesAPI on ApiClient {
|
||||||
Future<List<Package>> listPackages() async {
|
Future<List<Package>> listPackages({int? limit}) async {
|
||||||
final resp = await getRawClient().get("/packages/list");
|
final resp = await getRawClient()
|
||||||
|
.get("/packages/list", queryParameters: {'limit': limit});
|
||||||
|
|
||||||
final responseObject = resp.data as List;
|
final responseObject = resp.data as List;
|
||||||
final List<Package> packages =
|
final List<Package> packages =
|
||||||
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:visibility_detector/visibility_detector.dart';
|
|
||||||
|
|
||||||
import '../../providers/BaseProvider.dart';
|
import '../../providers/BaseProvider.dart';
|
||||||
|
|
||||||
@ -26,7 +25,6 @@ class APIBuilder<T extends BaseProvider, K, DTO> extends StatefulWidget {
|
|||||||
class _APIBuilderState<T extends BaseProvider, K, DTO>
|
class _APIBuilderState<T extends BaseProvider, K, DTO>
|
||||||
extends State<APIBuilder<T, K, DTO>> {
|
extends State<APIBuilder<T, K, DTO>> {
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
bool visible = true;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -35,10 +33,8 @@ class _APIBuilderState<T extends BaseProvider, K, DTO>
|
|||||||
|
|
||||||
if (widget.interval != null) {
|
if (widget.interval != null) {
|
||||||
timer = Timer.periodic(widget.interval!, (Timer t) {
|
timer = Timer.periodic(widget.interval!, (Timer t) {
|
||||||
if (visible) {
|
Provider.of<T>(context, listen: false)
|
||||||
Provider.of<T>(context, listen: false)
|
.refresh(context, dto: widget.dto);
|
||||||
.refresh(context, dto: widget.dto);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,30 +49,15 @@ class _APIBuilderState<T extends BaseProvider, K, DTO>
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Future<K> fut = Provider.of<T>(context).data as Future<K>;
|
final Future<K> fut = Provider.of<T>(context).data as Future<K>;
|
||||||
|
|
||||||
return VisibilityDetector(
|
return FutureBuilder<K>(
|
||||||
key: widget.key ?? const Key("APIBuilder"),
|
future: fut,
|
||||||
onVisibilityChanged: (visibilityInfo) {
|
builder: (context, snapshot) {
|
||||||
var visiblePercentage = visibilityInfo.visibleFraction * 100;
|
if (snapshot.hasData) {
|
||||||
|
return widget.onData(snapshot.data!);
|
||||||
if (mounted) {
|
} else {
|
||||||
setState(() {
|
return widget.onLoad();
|
||||||
visible = visiblePercentage != 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint(
|
|
||||||
'Widget ${visibilityInfo.key} is ${visiblePercentage}% visible');
|
|
||||||
},
|
},
|
||||||
child: FutureBuilder<K>(
|
|
||||||
future: fut,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return widget.onData(snapshot.data!);
|
|
||||||
} else {
|
|
||||||
return widget.onLoad();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:aurcache/api/builds.dart';
|
|
||||||
import 'package:aurcache/components/builds_table.dart';
|
import 'package:aurcache/components/builds_table.dart';
|
||||||
import 'package:aurcache/models/build.dart';
|
import 'package:aurcache/models/build.dart';
|
||||||
import 'package:aurcache/components/dashboard/your_packages.dart';
|
|
||||||
import 'package:aurcache/components/api/APIBuilder.dart';
|
import 'package:aurcache/components/api/APIBuilder.dart';
|
||||||
import 'package:aurcache/providers/builds_provider.dart';
|
import 'package:aurcache/providers/builds_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import '../../api/API.dart';
|
|
||||||
import '../../constants/color_constants.dart';
|
import '../../constants/color_constants.dart';
|
||||||
|
|
||||||
class RecentBuilds extends StatefulWidget {
|
class RecentBuilds extends StatefulWidget {
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:aurcache/api/packages.dart';
|
|
||||||
import 'package:aurcache/components/api/APIBuilder.dart';
|
import 'package:aurcache/components/api/APIBuilder.dart';
|
||||||
|
import 'package:aurcache/components/packages_table.dart';
|
||||||
import 'package:aurcache/providers/packages_provider.dart';
|
import 'package:aurcache/providers/packages_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import '../../api/API.dart';
|
|
||||||
import '../../constants/color_constants.dart';
|
import '../../constants/color_constants.dart';
|
||||||
import '../../models/package.dart';
|
import '../../models/package.dart';
|
||||||
import '../../providers/builds_provider.dart';
|
|
||||||
import '../../providers/stats_provider.dart';
|
|
||||||
import '../confirm_popup.dart';
|
|
||||||
|
|
||||||
class YourPackages extends StatefulWidget {
|
class YourPackages extends StatefulWidget {
|
||||||
const YourPackages({
|
const YourPackages({
|
||||||
@ -39,113 +31,33 @@ class _YourPackagesState extends State<YourPackages> {
|
|||||||
"Your Packages",
|
"Your Packages",
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
style: Theme.of(context).textTheme.subtitle1,
|
||||||
),
|
),
|
||||||
SingleChildScrollView(
|
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
//scrollDirection: Axis.horizontal,
|
SizedBox(
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: APIBuilder<PackagesProvider, List<Package>, Object>(
|
child: APIBuilder<PackagesProvider, List<Package>, PackagesDTO>(
|
||||||
key: Key("Packages on dashboard"),
|
key: const Key("Packages on dashboard"),
|
||||||
interval: const Duration(seconds: 10),
|
interval: const Duration(seconds: 10),
|
||||||
|
dto: PackagesDTO(limit: 10),
|
||||||
onData: (data) {
|
onData: (data) {
|
||||||
return DataTable(
|
return PackagesTable(data: data);
|
||||||
horizontalMargin: 0,
|
|
||||||
columnSpacing: defaultPadding,
|
|
||||||
columns: const [
|
|
||||||
DataColumn(
|
|
||||||
label: Text("Package ID"),
|
|
||||||
),
|
|
||||||
DataColumn(
|
|
||||||
label: Text("Package Name"),
|
|
||||||
),
|
|
||||||
DataColumn(
|
|
||||||
label: Text("Version"),
|
|
||||||
),
|
|
||||||
DataColumn(
|
|
||||||
label: Text("Up-To-Date"),
|
|
||||||
),
|
|
||||||
DataColumn(
|
|
||||||
label: Text("Status"),
|
|
||||||
),
|
|
||||||
DataColumn(
|
|
||||||
label: Text("Action"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
rows: data
|
|
||||||
.map((e) => buildDataRow(e))
|
|
||||||
.toList(growable: false));
|
|
||||||
},
|
},
|
||||||
onLoad: () => const Text("No data"),
|
onLoad: () => const Text("No data"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
context.push("/packages");
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"List all Packages",
|
||||||
|
style: TextStyle(color: Colors.white.withOpacity(0.8)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRow buildDataRow(Package package) {
|
|
||||||
return DataRow(
|
|
||||||
cells: [
|
|
||||||
DataCell(Text(package.id.toString())),
|
|
||||||
DataCell(Text(package.name)),
|
|
||||||
DataCell(Text(package.latest_version.toString())),
|
|
||||||
DataCell(IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
package.outofdate ? Icons.update : Icons.verified,
|
|
||||||
color: package.outofdate ? Color(0xFF6B43A4) : Color(0xFF0A6900),
|
|
||||||
),
|
|
||||||
onPressed: package.outofdate
|
|
||||||
? () {
|
|
||||||
// todo open build info with logs
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
)),
|
|
||||||
DataCell(IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
switchSuccessIcon(package.status),
|
|
||||||
color: switchSuccessColor(package.status),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
//context.push("/build/${package.latest_version_id}");
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
DataCell(
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
child: const Text('View', style: TextStyle(color: greenColor)),
|
|
||||||
onPressed: () {
|
|
||||||
context.push("/package/${package.id}");
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 6,
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: const Text("Delete",
|
|
||||||
style: TextStyle(color: Colors.redAccent)),
|
|
||||||
onPressed: () async {
|
|
||||||
final confirmResult =
|
|
||||||
await showDeleteConfirmationDialog(context);
|
|
||||||
if (!confirmResult) return;
|
|
||||||
|
|
||||||
final succ = await API.deletePackage(package.id);
|
|
||||||
if (succ) {
|
|
||||||
Provider.of<PackagesProvider>(context, listen: false)
|
|
||||||
.refresh(context);
|
|
||||||
Provider.of<BuildsProvider>(context, listen: false)
|
|
||||||
.refresh(context);
|
|
||||||
Provider.of<StatsProvider>(context, listen: false)
|
|
||||||
.refresh(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IconData switchSuccessIcon(int status) {
|
IconData switchSuccessIcon(int status) {
|
||||||
|
111
frontend/lib/components/packages_table.dart
Normal file
111
frontend/lib/components/packages_table.dart
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import 'package:aurcache/api/packages.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../api/API.dart';
|
||||||
|
import '../constants/color_constants.dart';
|
||||||
|
import '../models/package.dart';
|
||||||
|
import '../providers/builds_provider.dart';
|
||||||
|
import '../providers/packages_provider.dart';
|
||||||
|
import '../providers/stats_provider.dart';
|
||||||
|
import 'confirm_popup.dart';
|
||||||
|
import 'dashboard/your_packages.dart';
|
||||||
|
|
||||||
|
class PackagesTable extends StatelessWidget {
|
||||||
|
const PackagesTable({super.key, required this.data});
|
||||||
|
final List<Package> data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DataTable(
|
||||||
|
horizontalMargin: 0,
|
||||||
|
columnSpacing: defaultPadding,
|
||||||
|
columns: const [
|
||||||
|
DataColumn(
|
||||||
|
label: Text("Package ID"),
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: Text("Package Name"),
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: Text("Version"),
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: Text("Up-To-Date"),
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: Text("Status"),
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: Text("Action"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
rows:
|
||||||
|
data.map((e) => buildDataRow(e, context)).toList(growable: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
DataRow buildDataRow(Package package, BuildContext context) {
|
||||||
|
return DataRow(
|
||||||
|
cells: [
|
||||||
|
DataCell(Text(package.id.toString())),
|
||||||
|
DataCell(Text(package.name)),
|
||||||
|
DataCell(Text(package.latest_version.toString())),
|
||||||
|
DataCell(IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
package.outofdate ? Icons.update : Icons.verified,
|
||||||
|
color: package.outofdate ? Color(0xFF6B43A4) : Color(0xFF0A6900),
|
||||||
|
),
|
||||||
|
onPressed: package.outofdate
|
||||||
|
? () {
|
||||||
|
// todo open build info with logs
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
)),
|
||||||
|
DataCell(IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
switchSuccessIcon(package.status),
|
||||||
|
color: switchSuccessColor(package.status),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
//context.push("/build/${package.latest_version_id}");
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
DataCell(
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
child: const Text('View', style: TextStyle(color: greenColor)),
|
||||||
|
onPressed: () {
|
||||||
|
context.push("/package/${package.id}");
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 6,
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: const Text("Delete",
|
||||||
|
style: TextStyle(color: Colors.redAccent)),
|
||||||
|
onPressed: () async {
|
||||||
|
final confirmResult =
|
||||||
|
await showDeleteConfirmationDialog(context);
|
||||||
|
if (!confirmResult) return;
|
||||||
|
|
||||||
|
final succ = await API.deletePackage(package.id);
|
||||||
|
if (succ) {
|
||||||
|
Provider.of<PackagesProvider>(context, listen: false)
|
||||||
|
.refresh(context);
|
||||||
|
Provider.of<BuildsProvider>(context, listen: false)
|
||||||
|
.refresh(context);
|
||||||
|
Provider.of<StatsProvider>(context, listen: false)
|
||||||
|
.refresh(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import 'package:aurcache/screens/builds_screen.dart';
|
|||||||
import 'package:aurcache/screens/dashboard_screen.dart';
|
import 'package:aurcache/screens/dashboard_screen.dart';
|
||||||
import 'package:aurcache/components/routing/menu_shell.dart';
|
import 'package:aurcache/components/routing/menu_shell.dart';
|
||||||
import 'package:aurcache/screens/package_screen.dart';
|
import 'package:aurcache/screens/package_screen.dart';
|
||||||
|
import 'package:aurcache/screens/packages_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@ -35,6 +36,10 @@ final appRouter = GoRouter(
|
|||||||
path: '/builds',
|
path: '/builds',
|
||||||
builder: (context, state) => const BuildsScreen(),
|
builder: (context, state) => const BuildsScreen(),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/packages',
|
||||||
|
builder: (context, state) => const PackagesScreen(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/package/:id',
|
path: '/package/:id',
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
import 'package:aurcache/components/routing/router.dart';
|
import 'package:aurcache/components/routing/router.dart';
|
||||||
import 'package:aurcache/providers/build_provider.dart';
|
|
||||||
import 'package:aurcache/providers/builds_provider.dart';
|
|
||||||
import 'package:aurcache/providers/package_provider.dart';
|
|
||||||
import 'package:aurcache/providers/packages_provider.dart';
|
|
||||||
import 'package:aurcache/providers/stats_provider.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'constants/color_constants.dart';
|
import 'constants/color_constants.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -20,30 +14,18 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiProvider(
|
return MaterialApp.router(
|
||||||
providers: [
|
routerConfig: appRouter,
|
||||||
ChangeNotifierProvider<StatsProvider>(create: (_) => StatsProvider()),
|
debugShowCheckedModeBanner: false,
|
||||||
ChangeNotifierProvider<PackagesProvider>(
|
title: 'AURCache',
|
||||||
create: (_) => PackagesProvider()),
|
theme: ThemeData.dark().copyWith(
|
||||||
ChangeNotifierProvider<BuildsProvider>(create: (_) => BuildsProvider()),
|
appBarTheme: const AppBarTheme(backgroundColor: bgColor, elevation: 0),
|
||||||
ChangeNotifierProvider<PackageProvider>(
|
scaffoldBackgroundColor: bgColor,
|
||||||
create: (_) => PackageProvider()),
|
primaryColor: greenColor,
|
||||||
ChangeNotifierProvider<BuildProvider>(create: (_) => BuildProvider()),
|
dialogBackgroundColor: secondaryColor,
|
||||||
],
|
textTheme: GoogleFonts.openSansTextTheme(Theme.of(context).textTheme)
|
||||||
child: MaterialApp.router(
|
.apply(bodyColor: Colors.white),
|
||||||
routerConfig: appRouter,
|
canvasColor: secondaryColor,
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
title: 'AURCache',
|
|
||||||
theme: ThemeData.dark().copyWith(
|
|
||||||
appBarTheme:
|
|
||||||
const AppBarTheme(backgroundColor: bgColor, elevation: 0),
|
|
||||||
scaffoldBackgroundColor: bgColor,
|
|
||||||
primaryColor: greenColor,
|
|
||||||
dialogBackgroundColor: secondaryColor,
|
|
||||||
textTheme: GoogleFonts.openSansTextTheme(Theme.of(context).textTheme)
|
|
||||||
.apply(bodyColor: Colors.white),
|
|
||||||
canvasColor: secondaryColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,17 @@ import 'package:aurcache/api/packages.dart';
|
|||||||
import 'package:aurcache/providers/BaseProvider.dart';
|
import 'package:aurcache/providers/BaseProvider.dart';
|
||||||
|
|
||||||
import '../api/API.dart';
|
import '../api/API.dart';
|
||||||
|
import '../models/package.dart';
|
||||||
|
|
||||||
class PackagesProvider extends BaseProvider {
|
class PackagesDTO {
|
||||||
|
final int limit;
|
||||||
|
|
||||||
|
PackagesDTO({required this.limit});
|
||||||
|
}
|
||||||
|
|
||||||
|
class PackagesProvider extends BaseProvider<List<Package>, PackagesDTO> {
|
||||||
@override
|
@override
|
||||||
loadFuture(context, {dto}) {
|
loadFuture(context, {dto}) {
|
||||||
data = API.listPackages();
|
data = API.listPackages(limit: dto?.limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:aurcache/providers/build_provider.dart';
|
|||||||
import 'package:aurcache/utils/time_formatter.dart';
|
import 'package:aurcache/utils/time_formatter.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../components/dashboard/your_packages.dart';
|
import '../components/dashboard/your_packages.dart';
|
||||||
|
|
||||||
@ -21,54 +22,59 @@ class _BuildScreenState extends State<BuildScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: APIBuilder<BuildProvider, Build, BuildDTO>(
|
body: MultiProvider(
|
||||||
key: const Key("Build on seperate page"),
|
providers: [
|
||||||
dto: BuildDTO(buildID: widget.buildID),
|
ChangeNotifierProvider<BuildProvider>(create: (_) => BuildProvider()),
|
||||||
interval: const Duration(seconds: 10),
|
],
|
||||||
onLoad: () => const Text("loading"),
|
child: APIBuilder<BuildProvider, Build, BuildDTO>(
|
||||||
onData: (buildData) {
|
key: const Key("Build on seperate page"),
|
||||||
final start_time = DateTime.fromMillisecondsSinceEpoch(
|
dto: BuildDTO(buildID: widget.buildID),
|
||||||
(buildData.start_time ?? 0) * 1000);
|
interval: const Duration(seconds: 10),
|
||||||
|
onLoad: () => const Text("loading"),
|
||||||
|
onData: (buildData) {
|
||||||
|
final start_time = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(buildData.start_time ?? 0) * 1000);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
switchSuccessIcon(buildData.status),
|
|
||||||
color: switchSuccessColor(buildData.status),
|
|
||||||
),
|
),
|
||||||
onPressed: () {
|
IconButton(
|
||||||
context.replace("/build/${buildData.id}");
|
icon: Icon(
|
||||||
},
|
switchSuccessIcon(buildData.status),
|
||||||
),
|
color: switchSuccessColor(buildData.status),
|
||||||
const SizedBox(
|
),
|
||||||
width: 10,
|
onPressed: () {
|
||||||
),
|
context.replace("/build/${buildData.id}");
|
||||||
Text(
|
},
|
||||||
buildData.pkg_name,
|
),
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
const SizedBox(
|
||||||
),
|
width: 10,
|
||||||
const SizedBox(
|
),
|
||||||
width: 10,
|
Text(
|
||||||
),
|
buildData.pkg_name,
|
||||||
Text("triggered ${start_time.readableDuration()}")
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
],
|
),
|
||||||
),
|
const SizedBox(
|
||||||
const SizedBox(
|
width: 10,
|
||||||
height: 15,
|
),
|
||||||
),
|
Text("triggered ${start_time.readableDuration()}")
|
||||||
_buildPage(buildData)
|
],
|
||||||
],
|
),
|
||||||
);
|
const SizedBox(
|
||||||
}),
|
height: 15,
|
||||||
|
),
|
||||||
|
_buildPage(buildData)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
appBar: AppBar(),
|
appBar: AppBar(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import 'package:aurcache/components/builds_table.dart';
|
|||||||
import 'package:aurcache/components/api/APIBuilder.dart';
|
import 'package:aurcache/components/api/APIBuilder.dart';
|
||||||
import 'package:aurcache/providers/builds_provider.dart';
|
import 'package:aurcache/providers/builds_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import '../constants/color_constants.dart';
|
import '../constants/color_constants.dart';
|
||||||
import '../models/build.dart';
|
import '../models/build.dart';
|
||||||
|
|
||||||
@ -12,33 +13,39 @@ class BuildsScreen extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(),
|
appBar: AppBar(),
|
||||||
body: Padding(
|
body: MultiProvider(
|
||||||
padding: const EdgeInsets.all(defaultPadding),
|
providers: [
|
||||||
child: Container(
|
ChangeNotifierProvider<BuildsProvider>(
|
||||||
|
create: (_) => BuildsProvider()),
|
||||||
|
],
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(defaultPadding),
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
decoration: const BoxDecoration(
|
child: Container(
|
||||||
color: secondaryColor,
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
decoration: const BoxDecoration(
|
||||||
),
|
color: secondaryColor,
|
||||||
child: SingleChildScrollView(
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
child: Column(
|
),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: SingleChildScrollView(
|
||||||
children: [
|
child: Column(
|
||||||
Text(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
"All Builds",
|
children: [
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
Text(
|
||||||
),
|
"All Builds",
|
||||||
SizedBox(
|
style: Theme.of(context).textTheme.subtitle1,
|
||||||
width: double.infinity,
|
),
|
||||||
child: APIBuilder<BuildsProvider, List<Build>, Object>(
|
SizedBox(
|
||||||
key: const Key("Builds on seperate screen"),
|
width: double.infinity,
|
||||||
interval: const Duration(seconds: 10),
|
child: APIBuilder<BuildsProvider, List<Build>, Object>(
|
||||||
onLoad: () => const Text("no data"),
|
key: const Key("Builds on seperate screen"),
|
||||||
onData: (data) {
|
interval: const Duration(seconds: 10),
|
||||||
return BuildsTable(data: data);
|
onLoad: () => const Text("no data"),
|
||||||
}),
|
onData: (data) {
|
||||||
)
|
return BuildsTable(data: data);
|
||||||
],
|
}),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import 'package:aurcache/api/statistics.dart';
|
|
||||||
import 'package:aurcache/components/api/APIBuilder.dart';
|
import 'package:aurcache/components/api/APIBuilder.dart';
|
||||||
import 'package:aurcache/providers/stats_provider.dart';
|
import 'package:aurcache/providers/stats_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../api/API.dart';
|
|
||||||
import '../components/dashboard/header.dart';
|
import '../components/dashboard/header.dart';
|
||||||
import '../constants/color_constants.dart';
|
import '../constants/color_constants.dart';
|
||||||
|
import '../providers/builds_provider.dart';
|
||||||
|
import '../providers/packages_provider.dart';
|
||||||
import '../utils/responsive.dart';
|
import '../utils/responsive.dart';
|
||||||
import '../models/stats.dart';
|
import '../models/stats.dart';
|
||||||
import '../components/dashboard/quick_info_banner.dart';
|
import '../components/dashboard/quick_info_banner.dart';
|
||||||
@ -22,63 +22,71 @@ class DashboardScreen extends StatefulWidget {
|
|||||||
class _DashboardScreenState extends State<DashboardScreen> {
|
class _DashboardScreenState extends State<DashboardScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return APIBuilder<StatsProvider, Stats, Object>(
|
return MultiProvider(
|
||||||
interval: const Duration(seconds: 10),
|
providers: [
|
||||||
onData: (stats) {
|
ChangeNotifierProvider<StatsProvider>(create: (_) => StatsProvider()),
|
||||||
return SafeArea(
|
ChangeNotifierProvider<PackagesProvider>(
|
||||||
child: SingleChildScrollView(
|
create: (_) => PackagesProvider()),
|
||||||
child: Container(
|
ChangeNotifierProvider<BuildsProvider>(create: (_) => BuildsProvider()),
|
||||||
padding: const EdgeInsets.all(defaultPadding),
|
],
|
||||||
child: Column(
|
child: APIBuilder<StatsProvider, Stats, Object>(
|
||||||
children: [
|
interval: const Duration(seconds: 10),
|
||||||
const Header(),
|
onData: (stats) {
|
||||||
const SizedBox(height: defaultPadding),
|
return SafeArea(
|
||||||
QuickInfoBanner(
|
child: SingleChildScrollView(
|
||||||
stats: stats,
|
child: Container(
|
||||||
),
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
const SizedBox(height: defaultPadding),
|
child: Column(
|
||||||
Row(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
const Header(),
|
||||||
children: [
|
const SizedBox(height: defaultPadding),
|
||||||
Expanded(
|
QuickInfoBanner(
|
||||||
flex: 5,
|
stats: stats,
|
||||||
child: Column(
|
),
|
||||||
children: [
|
const SizedBox(height: defaultPadding),
|
||||||
const YourPackages(),
|
Row(
|
||||||
const SizedBox(height: defaultPadding),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
const RecentBuilds(),
|
children: [
|
||||||
if (Responsive.isMobile(context))
|
|
||||||
const SizedBox(height: defaultPadding),
|
|
||||||
if (Responsive.isMobile(context))
|
|
||||||
SidePanel(
|
|
||||||
nrbuilds: stats.total_builds,
|
|
||||||
nrfailedbuilds: stats.failed_builds,
|
|
||||||
nrActiveBuilds: stats.active_builds),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!Responsive.isMobile(context))
|
|
||||||
const SizedBox(width: defaultPadding),
|
|
||||||
// On Mobile means if the screen is less than 850 we dont want to show it
|
|
||||||
if (!Responsive.isMobile(context))
|
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 5,
|
||||||
child: SidePanel(
|
child: Column(
|
||||||
nrbuilds: stats.total_builds,
|
children: [
|
||||||
nrfailedbuilds: stats.failed_builds,
|
const YourPackages(),
|
||||||
nrActiveBuilds: stats.active_builds),
|
const SizedBox(height: defaultPadding),
|
||||||
|
const RecentBuilds(),
|
||||||
|
if (Responsive.isMobile(context))
|
||||||
|
const SizedBox(height: defaultPadding),
|
||||||
|
if (Responsive.isMobile(context))
|
||||||
|
SidePanel(
|
||||||
|
nrbuilds: stats.total_builds,
|
||||||
|
nrfailedbuilds: stats.failed_builds,
|
||||||
|
nrActiveBuilds: stats.active_builds),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
if (!Responsive.isMobile(context))
|
||||||
)
|
const SizedBox(width: defaultPadding),
|
||||||
],
|
// On Mobile means if the screen is less than 850 we dont want to show it
|
||||||
|
if (!Responsive.isMobile(context))
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: SidePanel(
|
||||||
|
nrbuilds: stats.total_builds,
|
||||||
|
nrfailedbuilds: stats.failed_builds,
|
||||||
|
nrActiveBuilds: stats.active_builds),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
onLoad: () {
|
||||||
onLoad: () {
|
return Text("loading");
|
||||||
return Text("loading");
|
},
|
||||||
},
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,94 +29,103 @@ class _PackageScreenState extends State<PackageScreen> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(),
|
appBar: AppBar(),
|
||||||
body: APIBuilder<PackageProvider, Package, PackageDTO>(
|
body: MultiProvider(
|
||||||
dto: PackageDTO(pkgID: widget.pkgID),
|
providers: [
|
||||||
onLoad: () => const Text("loading"),
|
ChangeNotifierProvider<BuildsProvider>(
|
||||||
onData: (pkg) {
|
create: (_) => BuildsProvider()),
|
||||||
return Padding(
|
ChangeNotifierProvider<PackageProvider>(
|
||||||
padding: const EdgeInsets.all(defaultPadding),
|
create: (_) => PackageProvider()),
|
||||||
child: Column(
|
],
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: APIBuilder<PackageProvider, Package, PackageDTO>(
|
||||||
children: [
|
dto: PackageDTO(pkgID: widget.pkgID),
|
||||||
Row(
|
onLoad: () => const Text("loading"),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
onData: (pkg) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
return Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
Container(
|
child: Column(
|
||||||
margin: const EdgeInsets.only(left: 15),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Text(
|
children: [
|
||||||
pkg.name,
|
Row(
|
||||||
style: const TextStyle(fontSize: 32),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
),
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
),
|
children: [
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(right: 15),
|
margin: const EdgeInsets.only(left: 15),
|
||||||
child: ElevatedButton(
|
child: Text(
|
||||||
onPressed: () async {
|
pkg.name,
|
||||||
final confirmResult =
|
style: const TextStyle(fontSize: 32),
|
||||||
await showDeleteConfirmationDialog(context);
|
|
||||||
if (!confirmResult) return;
|
|
||||||
|
|
||||||
final succ = await API.deletePackage(pkg.id);
|
|
||||||
if (succ) {
|
|
||||||
context.pop();
|
|
||||||
|
|
||||||
Provider.of<PackagesProvider>(context,
|
|
||||||
listen: false)
|
|
||||||
.refresh(context);
|
|
||||||
Provider.of<BuildsProvider>(context,
|
|
||||||
listen: false)
|
|
||||||
.refresh(context);
|
|
||||||
Provider.of<StatsProvider>(context, listen: false)
|
|
||||||
.refresh(context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
"Delete",
|
|
||||||
style: TextStyle(color: Colors.redAccent),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
Container(
|
||||||
],
|
margin: const EdgeInsets.only(right: 15),
|
||||||
),
|
child: ElevatedButton(
|
||||||
const SizedBox(
|
onPressed: () async {
|
||||||
height: 25,
|
final confirmResult =
|
||||||
),
|
await showDeleteConfirmationDialog(context);
|
||||||
Container(
|
if (!confirmResult) return;
|
||||||
padding: const EdgeInsets.all(defaultPadding),
|
|
||||||
decoration: const BoxDecoration(
|
final succ = await API.deletePackage(pkg.id);
|
||||||
color: secondaryColor,
|
if (succ) {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
context.pop();
|
||||||
),
|
|
||||||
child: SingleChildScrollView(
|
Provider.of<PackagesProvider>(context,
|
||||||
child: Column(
|
listen: false)
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
.refresh(context);
|
||||||
children: [
|
Provider.of<BuildsProvider>(context,
|
||||||
Text(
|
listen: false)
|
||||||
"Builds of ${pkg.name}",
|
.refresh(context);
|
||||||
style: Theme.of(context).textTheme.subtitle1,
|
Provider.of<StatsProvider>(context,
|
||||||
),
|
listen: false)
|
||||||
SizedBox(
|
.refresh(context);
|
||||||
width: double.infinity,
|
}
|
||||||
child: APIBuilder<BuildsProvider, List<Build>,
|
},
|
||||||
BuildsDTO>(
|
child: const Text(
|
||||||
key: const Key("Builds on Package info"),
|
"Delete",
|
||||||
dto: BuildsDTO(pkgID: pkg.id),
|
style: TextStyle(color: Colors.redAccent),
|
||||||
interval: const Duration(seconds: 5),
|
|
||||||
onData: (data) {
|
|
||||||
return BuildsTable(data: data);
|
|
||||||
},
|
|
||||||
onLoad: () => const Text("no data"),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
)
|
const SizedBox(
|
||||||
],
|
height: 25,
|
||||||
),
|
),
|
||||||
);
|
Container(
|
||||||
}),
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: secondaryColor,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Builds of ${pkg.name}",
|
||||||
|
style: Theme.of(context).textTheme.subtitle1,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: APIBuilder<BuildsProvider, List<Build>,
|
||||||
|
BuildsDTO>(
|
||||||
|
key: const Key("Builds on Package info"),
|
||||||
|
dto: BuildsDTO(pkgID: pkg.id),
|
||||||
|
interval: const Duration(seconds: 5),
|
||||||
|
onData: (data) {
|
||||||
|
return BuildsTable(data: data);
|
||||||
|
},
|
||||||
|
onLoad: () => const Text("no data"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
frontend/lib/screens/packages_screen.dart
Normal file
56
frontend/lib/screens/packages_screen.dart
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import 'package:aurcache/components/packages_table.dart';
|
||||||
|
import 'package:aurcache/providers/packages_provider.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../components/api/APIBuilder.dart';
|
||||||
|
import '../constants/color_constants.dart';
|
||||||
|
import '../models/package.dart';
|
||||||
|
|
||||||
|
class PackagesScreen extends StatelessWidget {
|
||||||
|
const PackagesScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: MultiProvider(
|
||||||
|
providers: [
|
||||||
|
ChangeNotifierProvider<PackagesProvider>(
|
||||||
|
create: (_) => PackagesProvider()),
|
||||||
|
],
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(defaultPadding),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: secondaryColor,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"All Packages",
|
||||||
|
style: Theme.of(context).textTheme.subtitle1,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: APIBuilder<PackagesProvider, List<Package>, Object>(
|
||||||
|
key: const Key("Builds on seperate screen"),
|
||||||
|
interval: const Duration(seconds: 10),
|
||||||
|
onLoad: () => const Text("no data"),
|
||||||
|
onData: (data) {
|
||||||
|
return PackagesTable(data: data);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user