mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-11-10 19:03:12 +00:00
refactor: Add colors to disks graph
This commit is contained in:
parent
bc121aa7ed
commit
eb3aaa4c62
|
@ -5,7 +5,7 @@ import 'package:selfprivacy/config/app_controller/app_controller.dart';
|
||||||
import 'package:selfprivacy/config/brand_colors.dart';
|
import 'package:selfprivacy/config/brand_colors.dart';
|
||||||
import 'package:selfprivacy/config/preferences_repository/inherited_preferences_repository.dart';
|
import 'package:selfprivacy/config/preferences_repository/inherited_preferences_repository.dart';
|
||||||
import 'package:selfprivacy/config/preferences_repository/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> {
|
class _AppControllerInjector extends InheritedNotifier<AppController> {
|
||||||
const _AppControllerInjector({
|
const _AppControllerInjector({
|
||||||
|
|
24
lib/theming/harmonized_basic_colors.dart
Normal file
24
lib/theming/harmonized_basic_colors.dart
Normal 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),
|
||||||
|
];
|
|
@ -7,6 +7,24 @@ class _Chart extends StatelessWidget {
|
||||||
final Period period = cubit.state.period;
|
final Period period = cubit.state.period;
|
||||||
final MetricsState state = cubit.state;
|
final MetricsState state = cubit.state;
|
||||||
List<Widget> charts;
|
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) {
|
if (state is MetricsLoaded || state is MetricsLoading) {
|
||||||
charts = [
|
charts = [
|
||||||
FilledCard(
|
FilledCard(
|
||||||
|
@ -146,66 +164,103 @@ class _Chart extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (state is MetricsLoaded && state.diskMetrics != null)
|
if (!(state is MetricsLoaded && state.diskMetrics == null))
|
||||||
FilledCard(
|
Builder(
|
||||||
clipped: false,
|
builder: (final context) {
|
||||||
child: Padding(
|
List<DiskGraphData> getDisksGraphData(
|
||||||
padding: const EdgeInsets.all(16.0),
|
final BuildContext context,
|
||||||
child: Column(
|
) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
if (state is! MetricsLoaded) {
|
||||||
children: [
|
return [];
|
||||||
Row(
|
}
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
final diskData = state.diskMetrics?.diskMetrics;
|
||||||
mainAxisSize: MainAxisSize.max,
|
if (diskData == null) {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
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: [
|
children: [
|
||||||
Flexible(
|
Row(
|
||||||
child: Text(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
'resource_chart.disk_title'.tr(),
|
mainAxisSize: MainAxisSize.max,
|
||||||
style:
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
Theme.of(context).textTheme.titleMedium?.copyWith(
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
'resource_chart.disk_title'.tr(),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium
|
||||||
|
?.copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurfaceVariant,
|
.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 8.0,
|
spacing: 8.0,
|
||||||
runSpacing: 8.0,
|
runSpacing: 8.0,
|
||||||
alignment: WrapAlignment.end,
|
alignment: WrapAlignment.end,
|
||||||
runAlignment: WrapAlignment.end,
|
runAlignment: WrapAlignment.end,
|
||||||
children: state.diskMetrics?.diskMetrics.keys
|
children: disksGraphData
|
||||||
.map<Widget>(
|
.map<Widget>(
|
||||||
(final diskId) => Legend(
|
(final disk) => Legend(
|
||||||
color:
|
color: disk.color,
|
||||||
Theme.of(context).colorScheme.primary,
|
text: disk.volume.displayName,
|
||||||
text: diskId,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.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) {
|
} 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;
|
final data = state.diskMetrics;
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
|
@ -321,7 +379,7 @@ Widget getDiskChart(final MetricsLoaded state) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: DiskChart(
|
child: DiskChart(
|
||||||
diskData: data.diskMetrics,
|
diskData: diskData,
|
||||||
period: state.period,
|
period: state.period,
|
||||||
start: state.metrics.start,
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:selfprivacy/logic/common_enum/common_enum.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/logic/models/metrics.dart';
|
||||||
import 'package:selfprivacy/ui/pages/server_details/charts/bottom_title.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 {
|
class DiskChart extends StatelessWidget {
|
||||||
const DiskChart({
|
const DiskChart({
|
||||||
|
@ -16,7 +16,7 @@ class DiskChart extends StatelessWidget {
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Map<String, List<TimeSeriesData>> diskData;
|
final List<DiskGraphData> diskData;
|
||||||
final Period period;
|
final Period period;
|
||||||
final DateTime start;
|
final DateTime start;
|
||||||
|
|
||||||
|
@ -34,10 +34,9 @@ class DiskChart extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(final BuildContext context) {
|
Widget build(final BuildContext context) {
|
||||||
final anyDiskId = diskData.keys.toList()[0];
|
|
||||||
final diskDataMax = [
|
final diskDataMax = [
|
||||||
...diskData.values.map<List<double>>(
|
...diskData.map<List<double>>(
|
||||||
(final timeData) => timeData.map((final e) => e.value).toList(),
|
(final disk) => disk.diskData.map((final e) => e.value).toList(),
|
||||||
),
|
),
|
||||||
].expand((final x) => x).reduce(max);
|
].expand((final x) => x).reduce(max);
|
||||||
return LineChart(
|
return LineChart(
|
||||||
|
@ -54,11 +53,11 @@ class DiskChart extends StatelessWidget {
|
||||||
bool timeShown = false;
|
bool timeShown = false;
|
||||||
for (final spot in touchedBarSpots) {
|
for (final spot in touchedBarSpots) {
|
||||||
final value = spot.y;
|
final value = spot.y;
|
||||||
final date = diskData[anyDiskId]![spot.x.toInt()].time;
|
final date = diskData.first.diskData[spot.x.toInt()].time;
|
||||||
|
|
||||||
res.add(
|
res.add(
|
||||||
LineTooltipItem(
|
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(
|
TextStyle(
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
@ -73,14 +72,13 @@ class DiskChart extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
lineBarsData: diskData.values
|
lineBarsData: diskData
|
||||||
.toList()
|
|
||||||
.map<LineChartBarData>(
|
.map<LineChartBarData>(
|
||||||
(final timeData) => LineChartBarData(
|
(final disk) => LineChartBarData(
|
||||||
spots: getSpots(timeData),
|
spots: getSpots(disk.diskData),
|
||||||
isCurved: false,
|
isCurved: false,
|
||||||
barWidth: 2,
|
barWidth: 2,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: disk.color,
|
||||||
dotData: const FlDotData(
|
dotData: const FlDotData(
|
||||||
show: false,
|
show: false,
|
||||||
),
|
),
|
||||||
|
@ -88,8 +86,8 @@ class DiskChart extends StatelessWidget {
|
||||||
show: true,
|
show: true,
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Theme.of(context).colorScheme.primary.withOpacity(0.5),
|
disk.color.withOpacity(0.5),
|
||||||
Theme.of(context).colorScheme.primary.withOpacity(0.0),
|
disk.color.withOpacity(0.0),
|
||||||
],
|
],
|
||||||
begin: Alignment.bottomCenter,
|
begin: Alignment.bottomCenter,
|
||||||
end: Alignment.topCenter,
|
end: Alignment.topCenter,
|
||||||
|
@ -114,7 +112,7 @@ class DiskChart extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
bottomTitle(
|
bottomTitle(
|
||||||
value.toInt(),
|
value.toInt(),
|
||||||
diskData[anyDiskId]!,
|
diskData.first.diskData,
|
||||||
period,
|
period,
|
||||||
),
|
),
|
||||||
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||||
|
|
|
@ -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/metrics/metrics_cubit.dart';
|
||||||
import 'package:selfprivacy/logic/cubit/server_detailed_info/server_detailed_info_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/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/brand_icons/brand_icons.dart';
|
||||||
import 'package:selfprivacy/ui/components/buttons/segmented_buttons.dart';
|
import 'package:selfprivacy/ui/components/buttons/segmented_buttons.dart';
|
||||||
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
import 'package:selfprivacy/ui/components/cards/filled_card.dart';
|
||||||
|
|
Loading…
Reference in a new issue