Initial charts rework

pull/116/head
Inex Code 2022-09-15 18:40:02 +03:00
parent 8039283f37
commit 03c38f637f
6 changed files with 234 additions and 166 deletions

View File

@ -0,0 +1,29 @@
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/models/hetzner_metrics.dart';
import 'package:intl/intl.dart';
String bottomTitle(
final int value,
final List<TimeSeriesData> data,
final Period period,
) {
final hhmm = DateFormat('HH:mm');
final day = DateFormat('MMMd');
String res;
if (value <= 0) {
return '';
}
final time = data[value].time;
switch (period) {
case Period.hour:
case Period.day:
res = hhmm.format(time);
break;
case Period.month:
res = day.format(time);
}
return res;
}

View File

@ -1,4 +1,4 @@
part of 'server_details_screen.dart';
part of '../server_details_screen.dart';
class _Chart extends StatelessWidget {
@override
@ -17,9 +17,25 @@ class _Chart extends StatelessWidget {
];
} else if (state is HetznerMetricsLoaded) {
charts = [
const Legend(color: Colors.red, text: 'CPU %'),
const SizedBox(height: 20),
getCpuChart(state),
BrandCards.filled(
clipped: false,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'CPU Usage',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 16),
getCpuChart(state),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [

View File

@ -0,0 +1,175 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/models/hetzner_metrics.dart';
import 'package:intl/intl.dart';
import 'package:selfprivacy/ui/pages/server_details/charts/bottom_title.dart';
class CpuChart extends StatelessWidget {
const CpuChart({
required this.data,
required this.period,
required this.start,
final super.key,
});
final List<TimeSeriesData> data;
final Period period;
final DateTime start;
List<FlSpot> getSpots() {
var i = 0;
final List<FlSpot> res = [];
for (final d in data) {
res.add(FlSpot(i.toDouble(), d.value));
i++;
}
return res;
}
@override
Widget build(final BuildContext context) => LineChart(
LineChartData(
lineTouchData: LineTouchData(
enabled: true,
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Theme.of(context).colorScheme.surface,
tooltipPadding: const EdgeInsets.all(8),
getTooltipItems: (final List<LineBarSpot> touchedBarSpots) {
final List<LineTooltipItem> res = [];
for (final spot in touchedBarSpots) {
final value = spot.y;
final date = data[spot.x.toInt()].time;
res.add(
LineTooltipItem(
'${value.toStringAsFixed(2)}% at ${DateFormat('HH:mm dd.MM.yyyy').format(date)}',
TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
);
}
return res;
},
),
),
lineBarsData: [
LineChartBarData(
spots: getSpots(),
isCurved: false,
barWidth: 2,
color: Theme.of(context).colorScheme.primary,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.primary.withOpacity(0.5),
Theme.of(context).colorScheme.primary.withOpacity(0.0),
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
),
),
],
minY: 0,
maxY: 100,
minX: data.length - 200,
titlesData: FlTitlesData(
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
interval: 40,
reservedSize: 30,
getTitlesWidget: (final value, final titleMeta) => Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
bottomTitle(
value.toInt(),
data,
period,
),
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
showTitles: true,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
rightTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: false,
),
),
),
gridData: FlGridData(
show: true,
drawVerticalLine: true,
horizontalInterval: 25,
verticalInterval: 40,
getDrawingHorizontalLine: (final value) => FlLine(
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
strokeWidth: 1,
),
getDrawingVerticalLine: (final value) => FlLine(
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
strokeWidth: 1,
),
),
borderData: FlBorderData(
show: true,
border: Border(
bottom: BorderSide(
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
width: 1,
),
left: BorderSide(
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
width: 1,
),
right: BorderSide(
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
width: 1,
),
top: BorderSide(
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
width: 1,
),
),
),
),
);
bool checkToShowTitle(
final double minValue,
final double maxValue,
final SideTitles sideTitles,
final double appliedInterval,
final double value,
) {
if (value < 0) {
return false;
} else if (value == 0) {
return true;
}
final localValue = value - minValue;
final v = localValue / 20;
return v - v.floor() == 0;
}
}

View File

@ -6,7 +6,7 @@ import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/models/hetzner_metrics.dart';
import 'package:intl/intl.dart';
import 'package:selfprivacy/ui/pages/server_details/charts/bottom_title.dart';
class NetworkChart extends StatelessWidget {
const NetworkChart({
@ -77,7 +77,11 @@ class NetworkChart extends StatelessWidget {
child: RotatedBox(
quarterTurns: 1,
child: Text(
bottomTitle(value.toInt()),
bottomTitle(
value.toInt(),
listData[0],
period,
),
style: const TextStyle(
fontSize: 10,
color: Colors.purple,
@ -135,26 +139,4 @@ class NetworkChart extends StatelessWidget {
final finalValue = diff / 20;
return finalValue - finalValue.floor() == 0;
}
String bottomTitle(final int value) {
final hhmm = DateFormat('HH:mm');
final day = DateFormat('MMMd');
String res;
if (value <= 0) {
return '';
}
final time = listData[0][value].time;
switch (period) {
case Period.hour:
case Period.day:
res = hhmm.format(time);
break;
case Period.month:
res = day.format(time);
}
return res;
}
}

View File

@ -1,135 +0,0 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/text_themes.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/models/hetzner_metrics.dart';
import 'package:intl/intl.dart';
class CpuChart extends StatelessWidget {
const CpuChart({
required this.data,
required this.period,
required this.start,
final super.key,
});
final List<TimeSeriesData> data;
final Period period;
final DateTime start;
List<FlSpot> getSpots() {
var i = 0;
final List<FlSpot> res = [];
for (final d in data) {
res.add(FlSpot(i.toDouble(), d.value));
i++;
}
return res;
}
@override
Widget build(final BuildContext context) => LineChart(
LineChartData(
lineTouchData: LineTouchData(enabled: false),
lineBarsData: [
LineChartBarData(
spots: getSpots(),
isCurved: true,
barWidth: 1,
color: Colors.red,
dotData: FlDotData(
show: false,
),
),
],
minY: 0,
maxY: 100,
minX: data.length - 200,
titlesData: FlTitlesData(
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
interval: 20,
reservedSize: 50,
getTitlesWidget: (final value, final titleMeta) => Padding(
padding: const EdgeInsets.all(8.0),
child: RotatedBox(
quarterTurns: 1,
child: Text(
bottomTitle(value.toInt()),
style: const TextStyle(
fontSize: 10,
color: Colors.purple,
fontWeight: FontWeight.bold,
),
),
),
),
showTitles: true,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
getTitlesWidget: (final value, final titleMeta) => Padding(
padding: const EdgeInsets.only(right: 15),
child: Text(
value.toInt().toString(),
style: progressTextStyleLight.copyWith(
color: Theme.of(context).brightness == Brightness.dark
? BrandColors.gray4
: null,
),
),
),
interval: 25,
showTitles: false,
),
),
),
gridData: FlGridData(show: true),
),
);
bool checkToShowTitle(
final double minValue,
final double maxValue,
final SideTitles sideTitles,
final double appliedInterval,
final double value,
) {
if (value < 0) {
return false;
} else if (value == 0) {
return true;
}
final localValue = value - minValue;
final v = localValue / 20;
return v - v.floor() == 0;
}
String bottomTitle(final int value) {
final hhmm = DateFormat('HH:mm');
final day = DateFormat('MMMd');
String res;
if (value <= 0) {
return '';
}
final time = data[value].time;
switch (period) {
case Period.hour:
case Period.day:
res = hhmm.format(time);
break;
case Period.month:
res = day.format(time);
}
return res;
}
}

View File

@ -9,6 +9,7 @@ import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_inf
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart';
import 'package:selfprivacy/logic/models/state_types.dart';
import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart';
import 'package:selfprivacy/ui/components/brand_header/brand_header.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart';
@ -22,10 +23,10 @@ import 'package:selfprivacy/utils/named_font_weight.dart';
import 'package:selfprivacy/utils/route_transitions/basic.dart';
import 'package:timezone/timezone.dart';
import 'package:selfprivacy/ui/pages/server_details/cpu_chart.dart';
import 'package:selfprivacy/ui/pages/server_details/network_charts.dart';
import 'package:selfprivacy/ui/pages/server_details/charts/cpu_chart.dart';
import 'package:selfprivacy/ui/pages/server_details/charts/network_charts.dart';
part 'chart.dart';
part 'charts/chart.dart';
part 'header.dart';
part 'server_settings.dart';
part 'text_details.dart';