mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-11-19 07:09:14 +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/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({
|
||||
|
|
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 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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue