Skip to content

Commit

Permalink
simplify design of apibuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukas-Heiligenbrunner committed Dec 2, 2024
1 parent a8d3353 commit 9bd3a9d
Show file tree
Hide file tree
Showing 21 changed files with 406 additions and 585 deletions.
2 changes: 1 addition & 1 deletion frontend/lib/api/aur.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'api_client.dart';
extension AURApi on ApiClient {
Future<List<AurPackage>> getAurPackages(String query) async {
final resp = await getRawClient().get("/search?query=$query");

print(resp);
final responseObject = resp.data as List;
final List<AurPackage> packages = responseObject
.map((e) => AurPackage.fromJson(e))
Expand Down
81 changes: 0 additions & 81 deletions frontend/lib/components/api/APIBuilder.dart

This file was deleted.

90 changes: 90 additions & 0 deletions frontend/lib/components/api/ApiBuilder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import 'dart:math';

import 'package:flutter/widgets.dart';
import 'package:toastification/toastification.dart';
import 'package:visibility_detector/visibility_detector.dart';

class APIController<T> extends ChangeNotifier {
void Function()? _refresh;

// Internal method to bind the refresh function from the state.
void _attachRefresh(void Function() refreshCallback) {
_refresh = refreshCallback;
}

// Public method to trigger a refresh.
void refresh() {
_refresh?.call();
notifyListeners();
}
}

class APIBuilder<T> extends StatefulWidget {
const APIBuilder(
{super.key,
this.interval,
required this.onLoad,
required this.onData,
required this.api,
this.controller});

final Duration? interval;
final Widget Function() onLoad;
final Widget Function(T data) onData;
final Future<T> Function() api;
final APIController<T>? controller;

@override
State<APIBuilder<T>> createState() => _APIBuilderState<T>();
}

class _APIBuilderState<T> extends State<APIBuilder<T>> {
late Future<T> _futureData;

@override
void initState() {
super.initState();
_futureData = widget.api();

// Attach the refresh callback to the controller.
widget.controller?._attachRefresh(_refreshData);
}

// Method to refresh data.
void _refreshData() {
setState(() {
_futureData = widget.api();
});
}

@override
Widget build(BuildContext context) {
return VisibilityDetector(
key: widget.key ?? Key(hashCode.toString()),
onVisibilityChanged: (VisibilityInfo info) {
if (info.visibleFraction > 0) {
_refreshData();
}
},
child: FutureBuilder<T>(
future: _futureData,
builder: (context, snapshot) {
if (snapshot.hasError) {
print(snapshot.error);
WidgetsBinding.instance
.addPostFrameCallback((_) => toastification.show(
title: Text('API Request failed! ${snapshot.error}'),
autoCloseDuration: const Duration(seconds: 5),
type: ToastificationType.error,
));
}
if (snapshot.hasData) {
return widget.onData(snapshot.data!);
} else {
return widget.onLoad();
}
},
),
);
}
}
18 changes: 11 additions & 7 deletions frontend/lib/components/dashboard/recent_builds.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import 'package:aurcache/api/builds.dart';
import 'package:aurcache/components/builds_table.dart';
import 'package:aurcache/models/build.dart';
import 'package:aurcache/components/api/APIBuilder.dart';
import 'package:aurcache/providers/api/builds_provider.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/build.dart';
import '../api/ApiBuilder.dart';
import '../table_info.dart';

class RecentBuilds extends StatelessWidget {
const RecentBuilds({super.key});

@override
Widget build(BuildContext context) {
final apiController =
Provider.of<APIController<List<Build>>>(context, listen: false);

return Container(
padding: const EdgeInsets.all(defaultPadding),
decoration: const BoxDecoration(
Expand All @@ -25,11 +30,9 @@ class RecentBuilds extends StatelessWidget {
"Recent Builds",
style: Theme.of(context).textTheme.titleMedium,
),
APIBuilder<BuildsProvider, List<Build>, BuildsDTO>(
key: const Key("Builds on dashboard"),
dto: BuildsDTO(limit: 10),
interval: const Duration(seconds: 10),
APIBuilder(
onLoad: () => const Text("no data"),
controller: apiController,
onData: (t) {
if (t.isEmpty) {
return const TableInfo(title: "You have no builds yet");
Expand All @@ -52,6 +55,7 @@ class RecentBuilds extends StatelessWidget {
);
}
},
api: () => API.listAllBuilds(limit: 10),
),
],
),
Expand Down
18 changes: 11 additions & 7 deletions frontend/lib/components/dashboard/your_packages.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import 'package:aurcache/components/api/APIBuilder.dart';
import 'package:aurcache/api/packages.dart';
import 'package:aurcache/components/packages_table.dart';
import 'package:aurcache/providers/api/packages_provider.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/simple_packge.dart';
import '../api/ApiBuilder.dart';
import '../table_info.dart';

class YourPackages extends StatelessWidget {
const YourPackages({super.key});
YourPackages({super.key});

@override
Widget build(BuildContext context) {
final apiController =
Provider.of<APIController<List<SimplePackage>>>(context, listen: false);

return Container(
padding: const EdgeInsets.all(defaultPadding),
decoration: const BoxDecoration(
Expand All @@ -25,10 +30,8 @@ class YourPackages extends StatelessWidget {
"Your Packages",
style: Theme.of(context).textTheme.titleMedium,
),
APIBuilder<PackagesProvider, List<SimplePackage>, PackagesDTO>(
key: const Key("Packages on dashboard"),
interval: const Duration(seconds: 10),
dto: PackagesDTO(limit: 10),
APIBuilder(
controller: apiController,
onData: (data) {
if (data.isEmpty) {
return const TableInfo(title: "You have no packages yet");
Expand All @@ -53,6 +56,7 @@ class YourPackages extends StatelessWidget {
}
},
onLoad: () => const CircularProgressIndicator(),
api: () => API.listPackages(limit: 10),
),
],
),
Expand Down
68 changes: 22 additions & 46 deletions frontend/lib/components/packages_table.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:aurcache/api/packages.dart';
import 'package:aurcache/components/api/ApiBuilder.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
Expand All @@ -7,12 +8,9 @@ import 'package:toastification/toastification.dart';

import '../api/API.dart';
import '../constants/color_constants.dart';
import '../models/build.dart';
import '../models/simple_packge.dart';
import '../providers/api/builds_provider.dart';
import '../providers/api/packages_provider.dart';
import '../providers/api/stats_provider.dart';
import '../utils/package_color.dart';
import 'confirm_popup.dart';

class PackagesTable extends StatelessWidget {
const PackagesTable({super.key, required this.data});
Expand Down Expand Up @@ -71,13 +69,22 @@ class PackagesTable extends StatelessWidget {
type: ToastificationType.error,
);
}
final apiController =
Provider.of<APIController<List<SimplePackage>>>(context,
listen: false);
apiController.refresh();

Provider.of<PackagesProvider>(context, listen: false)
.refresh(context);
Provider.of<BuildsProvider>(context, listen: false)
.refresh(context);
Provider.of<StatsProvider>(context, listen: false)
.refresh(context);
final buildsController =
Provider.of<APIController<List<Build>>>(context,
listen: false);
buildsController.refresh();

//Provider.of<PackagesProvider>(context, listen: false)
// .refresh(context);
//Provider.of<BuildsProvider>(context, listen: false)
// .refresh(context);
//Provider.of<StatsProvider>(context, listen: false)
// .refresh(context);
}
: null,
)),
Expand All @@ -91,42 +98,11 @@ class PackagesTable extends StatelessWidget {
},
)),
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 {
await showConfirmationDialog(context, "Delete Package",
"Are you sure to delete this Package?", () async {
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);
} else {
toastification.show(
title: Text('Failed to delete Package!'),
autoCloseDuration: const Duration(seconds: 5),
type: ToastificationType.error,
);
}
}, null);
},
),
],
TextButton(
child: const Text('View', style: TextStyle(color: greenColor)),
onPressed: () {
context.push("/package/${package.id}");
},
),
),
],
Expand Down
2 changes: 1 addition & 1 deletion frontend/lib/components/routing/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ final appRouter = GoRouter(
),
GoRoute(
path: '/packages',
builder: (context, state) => const PackagesScreen(),
builder: (context, state) => PackagesScreen(),
),
GoRoute(
path: '/aur',
Expand Down
13 changes: 0 additions & 13 deletions frontend/lib/providers/api/BaseProvider.dart

This file was deleted.

Loading

0 comments on commit 9bd3a9d

Please sign in to comment.