From f557569763dc7111d3a74d2bbf7b40bec16e4c56 Mon Sep 17 00:00:00 2001 From: lukas-heilgenbrunner Date: Tue, 10 Dec 2024 01:56:06 +0100 Subject: [PATCH] show new chart and recent activity on right panel --- frontend/assets/icons/tile/Frame.svg | 6 + frontend/assets/icons/tile/clock.svg | 8 + frontend/assets/icons/tile/folder.svg | 6 + frontend/assets/icons/tile/graph.svg | 6 + frontend/lib/components/activity_log.dart | 99 ++++++++++ .../api/{ApiBuilder.dart => api_builder.dart} | 0 frontend/lib/components/build_line_chart.dart | 182 ++++++++++++++++++ .../components/dashboard/builds_chart.dart | 117 ----------- .../dashboard/quick_info_banner.dart | 168 ++++++++++------ .../components/dashboard/quick_info_tile.dart | 127 +++++++----- .../components/dashboard/recent_builds.dart | 2 +- .../lib/components/dashboard/side_panel.dart | 95 ++++----- .../components/dashboard/your_packages.dart | 2 +- frontend/lib/components/packages_table.dart | 2 +- frontend/lib/models/quick_info_data.dart | 15 -- .../lib/screens/Package_settings_screen.dart | 2 +- frontend/lib/screens/aur_screen.dart | 2 +- frontend/lib/screens/build_screen.dart | 2 +- frontend/lib/screens/builds_screen.dart | 2 +- frontend/lib/screens/dashboard_screen.dart | 109 ++++++----- frontend/lib/screens/package_screen.dart | 2 +- frontend/lib/screens/packages_screen.dart | 2 +- frontend/pubspec.yaml | 1 + 23 files changed, 610 insertions(+), 347 deletions(-) create mode 100644 frontend/assets/icons/tile/Frame.svg create mode 100644 frontend/assets/icons/tile/clock.svg create mode 100644 frontend/assets/icons/tile/folder.svg create mode 100644 frontend/assets/icons/tile/graph.svg create mode 100644 frontend/lib/components/activity_log.dart rename frontend/lib/components/api/{ApiBuilder.dart => api_builder.dart} (100%) create mode 100644 frontend/lib/components/build_line_chart.dart delete mode 100644 frontend/lib/components/dashboard/builds_chart.dart delete mode 100644 frontend/lib/models/quick_info_data.dart diff --git a/frontend/assets/icons/tile/Frame.svg b/frontend/assets/icons/tile/Frame.svg new file mode 100644 index 0000000..ff41e24 --- /dev/null +++ b/frontend/assets/icons/tile/Frame.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/assets/icons/tile/clock.svg b/frontend/assets/icons/tile/clock.svg new file mode 100644 index 0000000..129e33a --- /dev/null +++ b/frontend/assets/icons/tile/clock.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/assets/icons/tile/folder.svg b/frontend/assets/icons/tile/folder.svg new file mode 100644 index 0000000..74fb4ec --- /dev/null +++ b/frontend/assets/icons/tile/folder.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/assets/icons/tile/graph.svg b/frontend/assets/icons/tile/graph.svg new file mode 100644 index 0000000..8c1a34b --- /dev/null +++ b/frontend/assets/icons/tile/graph.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/lib/components/activity_log.dart b/frontend/lib/components/activity_log.dart new file mode 100644 index 0000000..8f002fd --- /dev/null +++ b/frontend/lib/components/activity_log.dart @@ -0,0 +1,99 @@ +import 'package:aurcache/components/dashboard/header.dart'; +import 'package:aurcache/utils/responsive.dart'; +import 'package:flutter/material.dart'; + +class ActivityLog extends StatefulWidget { + const ActivityLog({super.key}); + + @override + State createState() => _ActivityLogState(); +} + +class _ActivityLogState extends State { + @override + Widget build(BuildContext context) { + return Column( + children: [ + ActivityLogItem( + text: "added Package \"Power\"", + timestamp: DateTime.timestamp(), + user: "Lukas Heiligenbrunner", + ), + ActivityLogItem( + text: "added Package \"Naps\"", + timestamp: DateTime.timestamp(), + user: "Evin Arslan", + ), + ActivityLogItem( + text: "added Package \"Not\"", + timestamp: DateTime.timestamp(), + user: "Sophie Francz", + ), + ActivityLogItem( + text: "added Package \"Powerapps\"", + timestamp: DateTime.timestamp(), + user: "Lukas Kessler", + ) + ], + ); + } +} + +class ActivityLogItem extends StatelessWidget { + const ActivityLogItem( + {super.key, this.user, required this.text, required this.timestamp}); + + final String? user; + final String text; + final DateTime timestamp; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Icon( + Icons.circle_outlined, + size: 16, + color: Color(0xff393C42), + ), + SizedBox( + width: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + user ?? "Unknown User", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 19), + ), + if (context.desktop) + SizedBox( + width: 5, + ), + if (context.desktop) + Text( + text, + style: TextStyle(fontSize: 16), + ) + ], + ), + context.desktop + ? Text( + timestamp.toString(), + style: TextStyle(fontSize: 15), + ) + : Text( + text, + style: TextStyle(fontSize: 16), + ) + ], + ), + ], + ), + ); + } +} diff --git a/frontend/lib/components/api/ApiBuilder.dart b/frontend/lib/components/api/api_builder.dart similarity index 100% rename from frontend/lib/components/api/ApiBuilder.dart rename to frontend/lib/components/api/api_builder.dart diff --git a/frontend/lib/components/build_line_chart.dart b/frontend/lib/components/build_line_chart.dart new file mode 100644 index 0000000..26471a8 --- /dev/null +++ b/frontend/lib/components/build_line_chart.dart @@ -0,0 +1,182 @@ +import 'package:aurcache/constants/color_constants.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; + +class BuildLineChart extends StatefulWidget { + const BuildLineChart({super.key}); + + @override + State createState() => _BuildLineChartState(); +} + +class _BuildLineChartState extends State { + List gradientColors = [ + Colors.purple, + Colors.deepPurpleAccent, + ]; + + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 2, + child: LineChart( + mainData(), + ), + ); + } + + Widget bottomTitleWidgets(double value, TitleMeta meta) { + const style = TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ); + Widget text; + switch (value.toInt()) { + case 2: + text = const Text('Aug', style: style); + break; + case 4: + text = const Text('Sep', style: style); + break; + case 6: + text = const Text('Oct', style: style); + break; + case 8: + text = const Text('Nov', style: style); + break; + case 10: + text = const Text('Dec', style: style); + break; + default: + text = const Text('', style: style); + break; + } + + return SideTitleWidget( + axisSide: meta.axisSide, + child: text, + ); + } + + Widget leftTitleWidgets(double value, TitleMeta meta) { + const style = TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + ); + String text; + switch (value.toInt()) { + case 0: + text = '10K'; + break; + case 3: + text = '30k'; + break; + case 5: + text = '50k'; + break; + default: + return Container(); + } + + return Text(text, style: style, textAlign: TextAlign.left); + } + + LineChartData mainData() { + return LineChartData( + gridData: FlGridData( + show: true, + drawVerticalLine: false, + horizontalInterval: 1, + verticalInterval: 1, + getDrawingHorizontalLine: (value) { + return const FlLine( + color: Colors.grey, strokeWidth: 1, dashArray: [5, 5]); + }, + ), + titlesData: FlTitlesData( + show: true, + rightTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 30, + interval: 1, + getTitlesWidget: bottomTitleWidgets, + ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + interval: 1, + getTitlesWidget: leftTitleWidgets, + reservedSize: 42, + ), + ), + ), + borderData: FlBorderData( + show: false, + ), + minX: 0, + maxX: 10, + minY: 0, + maxY: 6, + lineBarsData: [ + LineChartBarData( + spots: const [ + FlSpot(0, 3), + FlSpot(1, 1), + FlSpot(2, 2), + FlSpot(3, 1), + FlSpot(4, 4), + FlSpot(5, 2.5), + FlSpot(6, 1.7), + FlSpot(7, 2.1), + FlSpot(8, 3), + FlSpot(9, 4), + FlSpot(10, 3), + ], + isCurved: true, + gradient: LinearGradient( + colors: gradientColors, + ), + barWidth: 5, + isStrokeCapRound: true, + dotData: FlDotData( + show: true, + getDotPainter: (spot, percent, barData, index) { + Color dotColor = Color.lerp( + barData.gradient!.colors.first, + barData.gradient!.colors.last, + percent / 100, + )!; + + return FlDotCirclePainter( + radius: 6, + color: Colors.white, + strokeWidth: 3, + strokeColor: dotColor, + ); + }, + checkToShowDot: (spot, barData) { + // limitate which dot to sho + return true; + }, + ), + belowBarData: BarAreaData( + show: true, + gradient: LinearGradient( + colors: gradientColors + .map((color) => color.withOpacity(0.3)) + .toList(), + ), + ), + ), + ], + ); + } +} diff --git a/frontend/lib/components/dashboard/builds_chart.dart b/frontend/lib/components/dashboard/builds_chart.dart deleted file mode 100644 index fad5c9b..0000000 --- a/frontend/lib/components/dashboard/builds_chart.dart +++ /dev/null @@ -1,117 +0,0 @@ -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; - -class BuildsChart extends StatefulWidget { - const BuildsChart({ - super.key, - required this.nrBuilds, - required this.nrSuccessfulBuilds, - required this.nrfailedbuilds, - required this.nrEnqueuedBuilds, - }); - - final int nrBuilds; - final int nrSuccessfulBuilds; - final int nrfailedbuilds; - final int nrEnqueuedBuilds; - - @override - _BuildsChartState createState() => _BuildsChartState(); -} - -class _BuildsChartState extends State { - int touchedIndex = -1; - @override - Widget build(BuildContext context) { - return SizedBox( - height: 300, - child: AspectRatio( - aspectRatio: 1.3, - child: Row( - children: [ - const SizedBox( - height: 18, - ), - Expanded( - child: AspectRatio( - aspectRatio: 1, - child: PieChart( - PieChartData( - pieTouchData: PieTouchData( - touchCallback: (pieTouchResponse, touchresponse) { - setState(() { - // todo hover gesture not working properly - if (touchresponse?.touchedSection != null) { - touchedIndex = touchresponse! - .touchedSection!.touchedSectionIndex; - } else { - touchedIndex = -1; - } - }); - }), - borderData: FlBorderData( - show: false, - ), - sectionsSpace: 0, - centerSpaceRadius: 40, - sections: showingSections()), - ), - ), - ), - const SizedBox( - width: 28, - ), - ], - ), - ), - ); - } - - List showingSections() { - return List.generate(3, (i) { - final isTouched = i == touchedIndex; - final fontSize = isTouched ? 25.0 : 16.0; - final radius = isTouched ? 60.0 : 50.0; - switch (i) { - case 0: - return PieChartSectionData( - color: const Color(0xff760707), - value: widget.nrfailedbuilds.toDouble(), - title: - "${(widget.nrfailedbuilds * 100 / widget.nrBuilds).toStringAsFixed(2)}%", - radius: radius, - titleStyle: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.bold, - color: const Color(0xffffffff)), - ); - case 1: - return PieChartSectionData( - color: const Color(0xff0a7005), - value: (widget.nrSuccessfulBuilds).toDouble(), - title: - "${((widget.nrSuccessfulBuilds) * 100 / widget.nrBuilds).toStringAsFixed(2)}%", - radius: radius, - titleStyle: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.bold, - color: const Color(0xffffffff)), - ); - case 2: - return PieChartSectionData( - color: const Color(0xFF0044AA), - value: (widget.nrEnqueuedBuilds).toDouble(), - title: - "${((widget.nrEnqueuedBuilds) * 100 / widget.nrBuilds).toStringAsFixed(2)}%", - radius: radius, - titleStyle: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.bold, - color: const Color(0xffffffff)), - ); - default: - throw Error(); - } - }); - } -} diff --git a/frontend/lib/components/dashboard/quick_info_banner.dart b/frontend/lib/components/dashboard/quick_info_banner.dart index c8bb226..33ef163 100644 --- a/frontend/lib/components/dashboard/quick_info_banner.dart +++ b/frontend/lib/components/dashboard/quick_info_banner.dart @@ -2,9 +2,9 @@ import 'package:aurcache/components/dashboard/quick_info_tile.dart'; import 'package:aurcache/utils/file_formatter.dart'; import 'package:aurcache/utils/time_formatter.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import '../../constants/color_constants.dart'; -import '../../models/quick_info_data.dart'; import '../../utils/responsive.dart'; import '../../models/stats.dart'; @@ -18,65 +18,119 @@ class QuickInfoBanner extends StatelessWidget { @override Widget build(BuildContext context) { - final Size _size = MediaQuery.of(context).size; - return Column( - children: [ - const SizedBox(height: defaultPadding), - Responsive( - mobileChild: _buildBanner( - crossAxisCount: _size.width < 650 ? 2 : 4, - childAspectRatio: _size.width < 650 ? 1.2 : 1, - ), - desktopChild: _buildBanner( - childAspectRatio: _size.width < 1400 ? 2.75 : 2.75, - )) - ], - ); - } + final double iconSize = context.desktop ? 64 : 42; - List buildQuickInfoData() { - return [ - QuickInfoData( - color: primaryColor, - icon: Icons.widgets, - title: "Total Packages", - subtitle: stats.total_packages.toString()), - QuickInfoData( - color: const Color(0xFFFFA113), - icon: Icons.hourglass_top, - title: "Enqueued Builds", - subtitle: stats.enqueued_builds.toString()), - QuickInfoData( - color: const Color(0xFFA4CDFF), - icon: Icons.build, - title: "Total Builds", - subtitle: stats.total_builds.toString()), - QuickInfoData( - color: const Color(0xFFd50000), - icon: Icons.storage, - title: "Repo Size", - subtitle: stats.repo_storage_size.readableFileSize()), - QuickInfoData( - color: const Color(0xFF00F260), - icon: Icons.timelapse, - title: "Average Build Time", - subtitle: stats.avg_build_time.readableDuration()), + final items = [ + QuickInfoTile( + icon: SvgPicture.asset("assets/icons/tile/Frame.svg", + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + width: iconSize), + title: "Total Packages", + value: stats.total_packages.toString(), + positive: false, + trend: '10%', + ), + QuickInfoTile( + icon: SvgPicture.asset("assets/icons/tile/graph.svg", + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + width: iconSize), + title: "Total Builds", + value: stats.total_builds.toString(), + positive: true, + trend: '10%', + ), + QuickInfoTile( + icon: SvgPicture.asset("assets/icons/tile/clock.svg", + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + width: iconSize), + title: "Repo Size", + value: stats.repo_storage_size.readableFileSize(), + positive: true, + trend: '10%', + ), + QuickInfoTile( + icon: SvgPicture.asset("assets/icons/tile/folder.svg", + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + width: iconSize), + title: "Average Build Time", + value: stats.avg_build_time.readableDuration(), + positive: true, + trend: '10%', + ), + QuickInfoTile( + icon: AspectRatio( + aspectRatio: 1, + child: RotatedBox( + quarterTurns: 1, + child: CircularProgressIndicator( + value: 0.85, + strokeWidth: 8, + color: Colors.green, + backgroundColor: Color(0xff292e35), + ))), + title: "Build Success", + value: + "${(stats.total_builds != 0 ? (stats.successful_builds * 100 / stats.total_builds) : 0).toInt()}%", + positive: false, + trend: '10%', + ), ]; - } - Widget _buildBanner({int crossAxisCount = 5, double childAspectRatio = 1}) { - final quickInfo = buildQuickInfoData(); - return GridView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: quickInfo.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - crossAxisSpacing: defaultPadding, - mainAxisSpacing: defaultPadding, - childAspectRatio: childAspectRatio, - ), - itemBuilder: (context, idx) => QuickInfoTile(data: quickInfo[idx]), + return ResponsiveBuilder( + mobile: () { + return Column( + children: [ + items[0], + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + items[1], + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + items[2], + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + items[3], + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + items[4], + ], + ); + }, + desktop: () { + return Row( + children: [ + Expanded(child: items[0]), + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + Expanded(child: items[1]), + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + Expanded(child: items[2]), + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + Expanded(child: items[3]), + SizedBox( + width: defaultPadding, + height: defaultPadding, + ), + Expanded(child: items[4]), + ], + ); + }, ); } } diff --git a/frontend/lib/components/dashboard/quick_info_tile.dart b/frontend/lib/components/dashboard/quick_info_tile.dart index f5b66b5..28a58fb 100644 --- a/frontend/lib/components/dashboard/quick_info_tile.dart +++ b/frontend/lib/components/dashboard/quick_info_tile.dart @@ -1,12 +1,22 @@ -import 'package:aurcache/models/quick_info_data.dart'; +import 'package:aurcache/components/dashboard/header.dart'; +import 'package:aurcache/utils/responsive.dart'; import 'package:flutter/material.dart'; import '../../constants/color_constants.dart'; class QuickInfoTile extends StatefulWidget { - const QuickInfoTile({Key? key, required this.data}) : super(key: key); + const QuickInfoTile( + {super.key, + required this.icon, + required this.title, + required this.value, + required this.positive, + required this.trend}); - final QuickInfoData data; + final Widget icon; + final String title, value; + final bool positive; + final String trend; @override _QuickInfoTileState createState() => _QuickInfoTileState(); @@ -16,50 +26,79 @@ class _QuickInfoTileState extends State { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.all(defaultPadding), - decoration: const BoxDecoration( - color: secondaryColor, - borderRadius: BorderRadius.all(Radius.circular(10)), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - padding: const EdgeInsets.all(defaultPadding * 0.75), - height: 64, - width: 64, - decoration: BoxDecoration( - color: widget.data.color.withOpacity(0.1), - borderRadius: const BorderRadius.all(Radius.circular(10)), - ), - child: Icon( - widget.data.icon, - color: widget.data.color, - size: 32, + padding: const EdgeInsets.all(defaultPadding), + decoration: const BoxDecoration( + color: secondaryColor, + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.title, + style: TextStyle(fontSize: 18), ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 0), + child: Text( + widget.value, + style: TextStyle( + fontSize: context.desktop ? 36 : 24, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ), + if (context.desktop) + SizedBox( + height: 10, + ), + _buildTrend(), + ], + ), + SizedBox( + height: context.desktop ? 64 : 42, + child: widget.icon, + ) + ], + ) + ], + )); + } + + Widget _buildTrend() { + if (widget.positive) { + return Row( + children: [ + Icon( + Icons.keyboard_double_arrow_up_outlined, + color: Colors.lightGreen, ), - Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - widget.data.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleSmall, - ), - Text( - widget.data.subtitle, - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(color: Colors.white70), - ), - ], + Text( + widget.trend, + style: TextStyle(color: Colors.lightGreen), + ) + ], + ); + } else { + return Row( + children: [ + Icon( + Icons.keyboard_double_arrow_down_outlined, + color: Colors.red, ), + Text( + widget.trend, + style: TextStyle(color: Colors.red), + ) ], - ), - ); + ); + } } } diff --git a/frontend/lib/components/dashboard/recent_builds.dart b/frontend/lib/components/dashboard/recent_builds.dart index c15f8cd..01060e7 100644 --- a/frontend/lib/components/dashboard/recent_builds.dart +++ b/frontend/lib/components/dashboard/recent_builds.dart @@ -6,7 +6,7 @@ import 'package:provider/provider.dart'; import '../../api/API.dart'; import '../../constants/color_constants.dart'; import '../../models/build.dart'; -import '../api/ApiBuilder.dart'; +import '../api/api_builder.dart'; import '../table_info.dart'; class RecentBuilds extends StatelessWidget { diff --git a/frontend/lib/components/dashboard/side_panel.dart b/frontend/lib/components/dashboard/side_panel.dart index 99d3c14..5e44fcd 100644 --- a/frontend/lib/components/dashboard/side_panel.dart +++ b/frontend/lib/components/dashboard/side_panel.dart @@ -1,8 +1,9 @@ -import 'package:aurcache/components/dashboard/chart_card.dart'; +import 'package:aurcache/components/build_line_chart.dart'; +import 'package:aurcache/components/activity_log.dart'; +import 'package:aurcache/utils/responsive.dart'; import 'package:flutter/material.dart'; import '../../constants/color_constants.dart'; -import 'builds_chart.dart'; class SidePanel extends StatelessWidget { const SidePanel({ @@ -18,9 +19,7 @@ class SidePanel extends StatelessWidget { @override Widget build(BuildContext context) { - final nrBuilds = nrSuccessfulBuilds + nrfailedbuilds + nrEnqueuedBuilds; - - return Container( + final activityWidget = Container( padding: const EdgeInsets.all(defaultPadding), decoration: const BoxDecoration( color: secondaryColor, @@ -30,65 +29,49 @@ class SidePanel extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( - "Package build success", + "Recent Activity", style: TextStyle( fontSize: 18, fontWeight: FontWeight.w500, ), ), const SizedBox(height: defaultPadding), - nrBuilds > 0 - ? BuildsChart( - nrBuilds: nrBuilds, - nrSuccessfulBuilds: nrSuccessfulBuilds, - nrfailedbuilds: nrfailedbuilds, - nrEnqueuedBuilds: nrEnqueuedBuilds) - : const SizedBox( - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: 15, - ), - Icon( - Icons.info_outline_rounded, - size: 42, - ), - SizedBox( - height: 15, - ), - Text("Add Packages to view Graph"), - SizedBox( - height: 30, - ) - ], - ), - ), - SideCard( - color: const Color(0xff0a7005), - title: "Successful Builds", - textRight: - "${(nrBuilds != 0 ? (nrSuccessfulBuilds * 100 / nrBuilds) : 0).toStringAsFixed(2)}%", - subtitle: (nrSuccessfulBuilds).toString(), - ), - SideCard( - color: const Color(0xff760707), - title: "Failed Builds", - textRight: - "${(nrBuilds != 0 ? (nrfailedbuilds * 100 / nrBuilds) : 0).toStringAsFixed(2)}%", - subtitle: nrfailedbuilds.toString(), - ), - SideCard( - color: const Color(0xFF0044AA), - title: "Enqueued Builds", - textRight: - "${(nrBuilds != 0 ? (nrEnqueuedBuilds * 100 / nrBuilds) : 0).toStringAsFixed(2)}%", - subtitle: nrEnqueuedBuilds.toString(), - ), + ActivityLog() ], ), ); + + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + padding: const EdgeInsets.all(defaultPadding), + decoration: const BoxDecoration( + color: secondaryColor, + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Builds Per Month", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: defaultPadding), + BuildLineChart() + ], + ), + ), + SizedBox( + height: defaultPadding, + ), + Responsive( + mobileChild: activityWidget, + desktopChild: Expanded(child: activityWidget)) + ], + ); } } diff --git a/frontend/lib/components/dashboard/your_packages.dart b/frontend/lib/components/dashboard/your_packages.dart index 752671d..f16f588 100644 --- a/frontend/lib/components/dashboard/your_packages.dart +++ b/frontend/lib/components/dashboard/your_packages.dart @@ -6,7 +6,7 @@ import 'package:provider/provider.dart'; import '../../api/API.dart'; import '../../constants/color_constants.dart'; import '../../models/simple_packge.dart'; -import '../api/ApiBuilder.dart'; +import '../api/api_builder.dart'; import '../table_info.dart'; class YourPackages extends StatelessWidget { diff --git a/frontend/lib/components/packages_table.dart b/frontend/lib/components/packages_table.dart index 265ce1f..09cc085 100644 --- a/frontend/lib/components/packages_table.dart +++ b/frontend/lib/components/packages_table.dart @@ -1,5 +1,5 @@ import 'package:aurcache/api/packages.dart'; -import 'package:aurcache/components/api/ApiBuilder.dart'; +import 'package:aurcache/components/api/api_builder.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; diff --git a/frontend/lib/models/quick_info_data.dart b/frontend/lib/models/quick_info_data.dart deleted file mode 100644 index 25c80e4..0000000 --- a/frontend/lib/models/quick_info_data.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class QuickInfoData { - const QuickInfoData({ - Key? key, - required this.color, - required this.icon, - required this.title, - required this.subtitle, - }); - - final Color color; - final IconData icon; - final String title, subtitle; -} diff --git a/frontend/lib/screens/Package_settings_screen.dart b/frontend/lib/screens/Package_settings_screen.dart index 7eb6d3a..41f1a9d 100644 --- a/frontend/lib/screens/Package_settings_screen.dart +++ b/frontend/lib/screens/Package_settings_screen.dart @@ -7,7 +7,7 @@ import 'package:provider/provider.dart'; import 'package:toastification/toastification.dart'; import '../api/API.dart'; -import '../components/api/ApiBuilder.dart'; +import '../components/api/api_builder.dart'; import '../models/extended_package.dart'; class Packagesettingsscreen extends StatefulWidget { diff --git a/frontend/lib/screens/aur_screen.dart b/frontend/lib/screens/aur_screen.dart index d710a7e..d21ee80 100644 --- a/frontend/lib/screens/aur_screen.dart +++ b/frontend/lib/screens/aur_screen.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../api/API.dart'; -import '../components/api/ApiBuilder.dart'; +import '../components/api/api_builder.dart'; import '../constants/color_constants.dart'; class AurScreen extends StatefulWidget { diff --git a/frontend/lib/screens/build_screen.dart b/frontend/lib/screens/build_screen.dart index 3acd950..80f2ce7 100644 --- a/frontend/lib/screens/build_screen.dart +++ b/frontend/lib/screens/build_screen.dart @@ -10,7 +10,7 @@ import 'package:provider/provider.dart'; import 'package:toastification/toastification.dart'; import '../api/API.dart'; -import '../components/api/ApiBuilder.dart'; +import '../components/api/api_builder.dart'; import '../components/confirm_popup.dart'; import '../components/dashboard/chart_card.dart'; import '../constants/color_constants.dart'; diff --git a/frontend/lib/screens/builds_screen.dart b/frontend/lib/screens/builds_screen.dart index 8833a2c..0568d76 100644 --- a/frontend/lib/screens/builds_screen.dart +++ b/frontend/lib/screens/builds_screen.dart @@ -3,7 +3,7 @@ import 'package:aurcache/components/builds_table.dart'; import 'package:aurcache/components/table_info.dart'; import 'package:flutter/material.dart'; import '../api/API.dart'; -import '../components/api/ApiBuilder.dart'; +import '../components/api/api_builder.dart'; import '../constants/color_constants.dart'; import '../models/build.dart'; diff --git a/frontend/lib/screens/dashboard_screen.dart b/frontend/lib/screens/dashboard_screen.dart index 360015e..c3cc77e 100644 --- a/frontend/lib/screens/dashboard_screen.dart +++ b/frontend/lib/screens/dashboard_screen.dart @@ -1,5 +1,5 @@ import 'package:aurcache/api/statistics.dart'; -import 'package:aurcache/components/api/ApiBuilder.dart'; +import 'package:aurcache/components/api/api_builder.dart'; import 'package:aurcache/models/simple_packge.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -26,10 +26,55 @@ class _DashboardScreenState extends State { interval: const Duration(seconds: 10), onData: (stats) { return SafeArea( - child: SingleChildScrollView( - child: Container( + child: Builder(builder: (context) { + final body = MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => APIController>(), + ), + ChangeNotifierProvider( + create: (context) => APIController>(), + ), + ], + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 3, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + YourPackages(), + const SizedBox(height: defaultPadding), + const RecentBuilds(), + if (context.mobile) + const SizedBox(height: defaultPadding), + if (context.mobile) + SidePanel( + nrSuccessfulBuilds: stats.successful_builds, + nrfailedbuilds: stats.failed_builds, + nrEnqueuedBuilds: stats.enqueued_builds), + ], + ), + ), + if (!context.mobile) const SizedBox(width: defaultPadding), + // On Mobile means if the screen is less than 850 we dont want to show it + if (!context.mobile) + Expanded( + flex: 2, + child: SidePanel( + nrSuccessfulBuilds: stats.successful_builds, + nrfailedbuilds: stats.failed_builds, + nrEnqueuedBuilds: stats.enqueued_builds), + ), + ], + ), + ); + + final allScreen = Container( padding: const EdgeInsets.all(defaultPadding), child: Column( + mainAxisAlignment: MainAxisAlignment.start, children: [ const Header(), const SizedBox(height: defaultPadding), @@ -37,54 +82,20 @@ class _DashboardScreenState extends State { stats: stats, ), const SizedBox(height: defaultPadding), - MultiProvider( - providers: [ - ChangeNotifierProvider( - create: (context) => - APIController>(), - ), - ChangeNotifierProvider( - create: (context) => APIController>(), - ), - ], - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 5, - child: Column( - children: [ - YourPackages(), - const SizedBox(height: defaultPadding), - const RecentBuilds(), - if (context.mobile) - const SizedBox(height: defaultPadding), - if (context.mobile) - SidePanel( - nrSuccessfulBuilds: stats.successful_builds, - nrfailedbuilds: stats.failed_builds, - nrEnqueuedBuilds: stats.enqueued_builds), - ], - ), - ), - if (!context.mobile) - const SizedBox(width: defaultPadding), - // On Mobile means if the screen is less than 850 we dont want to show it - if (!context.mobile) - Expanded( - flex: 2, - child: SidePanel( - nrSuccessfulBuilds: stats.successful_builds, - nrfailedbuilds: stats.failed_builds, - nrEnqueuedBuilds: stats.enqueued_builds), - ), - ], - ), - ) + Responsive( + mobileChild: body, desktopChild: Expanded(child: body)) ], ), - ), - ), + ); + + if (context.mobile) { + return SingleChildScrollView( + child: allScreen, + ); + } else { + return allScreen; + } + }), ); }, onLoad: () { diff --git a/frontend/lib/screens/package_screen.dart b/frontend/lib/screens/package_screen.dart index c66c5e6..c00751b 100644 --- a/frontend/lib/screens/package_screen.dart +++ b/frontend/lib/screens/package_screen.dart @@ -8,7 +8,7 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import '../api/API.dart'; -import '../components/api/ApiBuilder.dart'; +import '../components/api/api_builder.dart'; import '../components/builds_table.dart'; import '../components/confirm_popup.dart'; import '../constants/color_constants.dart'; diff --git a/frontend/lib/screens/packages_screen.dart b/frontend/lib/screens/packages_screen.dart index 6188b23..dc85632 100644 --- a/frontend/lib/screens/packages_screen.dart +++ b/frontend/lib/screens/packages_screen.dart @@ -3,7 +3,7 @@ import 'package:aurcache/components/packages_table.dart'; import 'package:flutter/material.dart'; import '../api/API.dart'; -import '../components/api/ApiBuilder.dart'; +import '../components/api/api_builder.dart'; import '../constants/color_constants.dart'; class PackagesScreen extends StatelessWidget { diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 7b977d1..0abeb8e 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -70,6 +70,7 @@ flutter: uses-material-design: true assets: - assets/icons/ + - assets/icons/tile/ # To add assets to your application, add an assets section, like this: # assets: