refactor: Add colors to disks graph

This commit is contained in:
Inex Code 2024-08-06 18:25:05 +03:00
parent bc121aa7ed
commit eb3aaa4c62
6 changed files with 164 additions and 67 deletions

View file

@ -5,7 +5,7 @@ import 'package:selfprivacy/config/app_controller/app_controller.dart';
import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/preferences_repository/inherited_preferences_repository.dart';
import 'package:selfprivacy/config/preferences_repository/preferences_repository.dart';
import 'package:selfprivacy/theming/factory/app_theme_factory.dart';
import 'package:selfprivacy/theming/app_theme_factory.dart';
class _AppControllerInjector extends InheritedNotifier<AppController> {
const _AppControllerInjector({

View file

@ -0,0 +1,24 @@
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
List<Color> harmonizedBasicColors(final BuildContext context) => [
Colors.red.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.green.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.blue.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.purple.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.indigo.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.teal.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.amber.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.deepOrange.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.pink.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.deepPurple.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.cyan.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.lime.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.yellow.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.orange.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.lightBlue.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.lightGreen.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.brown.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.blueGrey.harmonizeWith(Theme.of(context).colorScheme.primary),
Colors.grey.harmonizeWith(Theme.of(context).colorScheme.primary),
];

View file

@ -7,6 +7,24 @@ class _Chart extends StatelessWidget {
final Period period = cubit.state.period;
final MetricsState state = cubit.state;
List<Widget> charts;
List<Color> getGraphColors(final BuildContext context, final int length) {
final colors = [
Theme.of(context).colorScheme.primary,
Theme.of(context).colorScheme.tertiary,
Theme.of(context).colorScheme.secondary,
...harmonizedBasicColors(context),
];
if (length <= colors.length) {
return colors.sublist(0, length);
} else {
return List.generate(
length,
(final index) => colors[index % colors.length],
);
}
}
if (state is MetricsLoaded || state is MetricsLoading) {
charts = [
FilledCard(
@ -146,66 +164,103 @@ class _Chart extends StatelessWidget {
),
),
const SizedBox(height: 8),
if (state is MetricsLoaded && state.diskMetrics != null)
FilledCard(
clipped: false,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
if (!(state is MetricsLoaded && state.diskMetrics == null))
Builder(
builder: (final context) {
List<DiskGraphData> getDisksGraphData(
final BuildContext context,
) {
if (state is! MetricsLoaded) {
return [];
}
final diskData = state.diskMetrics?.diskMetrics;
if (diskData == null) {
return [];
}
final List<DiskGraphData> res = [];
final colors = getGraphColors(context, diskData.keys.length);
for (final entry in diskData.entries) {
res.add(
DiskGraphData(
volume: context
.read<VolumesBloc>()
.state
.getVolume(entry.key.split('/').last),
color: colors[diskData.keys.toList().indexOf(entry.key)],
diskData: entry.value,
originalId: entry.key,
),
);
}
return res;
}
final disksGraphData = getDisksGraphData(context);
return FilledCard(
clipped: false,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
child: Text(
'resource_chart.disk_title'.tr(),
style:
Theme.of(context).textTheme.titleMedium?.copyWith(
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Text(
'resource_chart.disk_title'.tr(),
style: Theme.of(context)
.textTheme
.titleMedium
?.copyWith(
color: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
),
Flexible(
fit: FlexFit.loose,
child: Wrap(
spacing: 8.0,
runSpacing: 8.0,
alignment: WrapAlignment.end,
runAlignment: WrapAlignment.end,
children: state.diskMetrics?.diskMetrics.keys
),
),
Flexible(
fit: FlexFit.loose,
child: Wrap(
spacing: 8.0,
runSpacing: 8.0,
alignment: WrapAlignment.end,
runAlignment: WrapAlignment.end,
children: disksGraphData
.map<Widget>(
(final diskId) => Legend(
color:
Theme.of(context).colorScheme.primary,
text: diskId,
(final disk) => Legend(
color: disk.color,
text: disk.volume.displayName,
),
)
.toList() ??
[],
),
.toList(),
),
),
],
),
const SizedBox(height: 20),
Stack(
alignment: Alignment.center,
children: [
if (state is MetricsLoaded &&
state.diskMetrics != null)
getDiskChart(state, disksGraphData),
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: state is MetricsLoading ? 1 : 0,
child: const _GraphLoadingCardContent(),
),
],
),
],
),
const SizedBox(height: 20),
Stack(
alignment: Alignment.center,
children: [
getDiskChart(state),
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: state is MetricsLoading ? 1 : 0,
child: const _GraphLoadingCardContent(),
),
],
),
],
),
),
),
);
},
),
];
} else if (state is MetricsUnsupported) {
@ -311,7 +366,10 @@ class _Chart extends StatelessWidget {
}
}
Widget getDiskChart(final MetricsLoaded state) {
Widget getDiskChart(
final MetricsLoaded state,
final List<DiskGraphData> diskData,
) {
final data = state.diskMetrics;
if (data == null) {
@ -321,7 +379,7 @@ Widget getDiskChart(final MetricsLoaded state) {
return SizedBox(
height: 200,
child: DiskChart(
diskData: data.diskMetrics,
diskData: diskData,
period: state.period,
start: state.metrics.start,
),
@ -383,3 +441,17 @@ class _ColoredBox extends StatelessWidget {
),
);
}
class DiskGraphData {
DiskGraphData({
required this.volume,
required this.color,
required this.diskData,
required this.originalId,
});
final DiskVolume volume;
final Color color;
final List<TimeSeriesData> diskData;
final String originalId;
}

View file

@ -4,9 +4,9 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/metrics.dart';
import 'package:selfprivacy/ui/pages/server_details/charts/bottom_title.dart';
import 'package:selfprivacy/ui/pages/server_details/server_details_screen.dart';
class DiskChart extends StatelessWidget {
const DiskChart({
@ -16,7 +16,7 @@ class DiskChart extends StatelessWidget {
super.key,
});
final Map<String, List<TimeSeriesData>> diskData;
final List<DiskGraphData> diskData;
final Period period;
final DateTime start;
@ -34,10 +34,9 @@ class DiskChart extends StatelessWidget {
@override
Widget build(final BuildContext context) {
final anyDiskId = diskData.keys.toList()[0];
final diskDataMax = [
...diskData.values.map<List<double>>(
(final timeData) => timeData.map((final e) => e.value).toList(),
...diskData.map<List<double>>(
(final disk) => disk.diskData.map((final e) => e.value).toList(),
),
].expand((final x) => x).reduce(max);
return LineChart(
@ -54,11 +53,11 @@ class DiskChart extends StatelessWidget {
bool timeShown = false;
for (final spot in touchedBarSpots) {
final value = spot.y;
final date = diskData[anyDiskId]![spot.x.toInt()].time;
final date = diskData.first.diskData[spot.x.toInt()].time;
res.add(
LineTooltipItem(
'${timeShown ? '' : DateFormat('HH:mm dd.MM.yyyy').format(date)} ${diskData.keys.toList()[spot.barIndex]} ${value.toInt()}%',
'${timeShown ? '' : DateFormat('HH:mm dd.MM.yyyy').format(date)} ${diskData[spot.barIndex].volume.displayName} ${value.toInt()}%',
TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
@ -73,14 +72,13 @@ class DiskChart extends StatelessWidget {
},
),
),
lineBarsData: diskData.values
.toList()
lineBarsData: diskData
.map<LineChartBarData>(
(final timeData) => LineChartBarData(
spots: getSpots(timeData),
(final disk) => LineChartBarData(
spots: getSpots(disk.diskData),
isCurved: false,
barWidth: 2,
color: Theme.of(context).colorScheme.primary,
color: disk.color,
dotData: const FlDotData(
show: false,
),
@ -88,8 +86,8 @@ class DiskChart extends StatelessWidget {
show: true,
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.primary.withOpacity(0.5),
Theme.of(context).colorScheme.primary.withOpacity(0.0),
disk.color.withOpacity(0.5),
disk.color.withOpacity(0.0),
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
@ -114,7 +112,7 @@ class DiskChart extends StatelessWidget {
child: Text(
bottomTitle(
value.toInt(),
diskData[anyDiskId]!,
diskData.first.diskData,
period,
),
style: Theme.of(context).textTheme.labelSmall?.copyWith(

View file

@ -7,6 +7,9 @@ import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/metrics/metrics_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/models/disk_status.dart';
import 'package:selfprivacy/logic/models/metrics.dart';
import 'package:selfprivacy/theming/harmonized_basic_colors.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:selfprivacy/ui/components/buttons/segmented_buttons.dart';
import 'package:selfprivacy/ui/components/cards/filled_card.dart';