| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import 'dart:async';
- import 'package:flutter/material.dart';
- import 'package:intl/intl.dart';
- import 'package:provider/provider.dart';
- import '../../../core/theme/app_colors.dart';
- import '../../../core/widgets/app_icon.dart';
- import '../../../core/widgets/pressable.dart';
- import '../../home/gps_speed_controller.dart';
- import '../../home/obd_controller.dart';
- import '../../home/telemetry_settings_controller.dart';
- import '../../home/weather_controller.dart';
- /// Time, speed, temperature and a Home shortcut for the Jellyfin pages.
- class JellyfinStatusStrip extends StatefulWidget {
- const JellyfinStatusStrip({super.key});
- @override
- State<JellyfinStatusStrip> createState() => _JellyfinStatusStripState();
- }
- class _JellyfinStatusStripState extends State<JellyfinStatusStrip> {
- late DateTime _now = DateTime.now();
- Timer? _timer;
- @override
- void initState() {
- super.initState();
- _scheduleTick();
- }
- void _scheduleTick() {
- _timer?.cancel();
- final now = DateTime.now();
- final next = DateTime(
- now.year,
- now.month,
- now.day,
- now.hour,
- now.minute,
- ).add(const Duration(minutes: 1));
- _timer = Timer(next.difference(now) + const Duration(milliseconds: 80), () {
- if (!mounted) return;
- setState(() => _now = DateTime.now());
- _scheduleTick();
- });
- }
- @override
- void dispose() {
- _timer?.cancel();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- final colors = context.colors;
- final theme = Theme.of(context);
- final telemetry = context.watch<TelemetrySettingsController>();
- final obd = context.watch<ObdController>();
- final gps = context.watch<GpsSpeedController>();
- final weather = context.watch<WeatherController>();
- final useObdSpeed =
- telemetry.speedEnabled && telemetry.speedUseObd && obd.hasTelemetry;
- final speed = !telemetry.speedEnabled
- ? null
- : useObdSpeed
- ? obd.speedKmh
- : gps.speedKmh;
- final useObdTemperature =
- telemetry.temperatureUseObd && obd.ambientCelsius != null;
- final temperature = !telemetry.temperatureEnabled
- ? null
- : useObdTemperature
- ? obd.ambientCelsius
- : (weather.hasTemperature ? weather.temperatureCelsius : null);
- final locale = Localizations.localeOf(context).toLanguageTag();
- final use24Hour = MediaQuery.alwaysUse24HourFormatOf(context);
- final time = (use24Hour ? DateFormat.Hm(locale) : DateFormat.jm(locale))
- .format(_now);
- return Container(
- key: const ValueKey('jellyfin-status-strip'),
- padding: const EdgeInsets.fromLTRB(16, 8, 8, 8),
- decoration: BoxDecoration(
- color: colors.surface.withValues(alpha: 0.82),
- borderRadius: BorderRadius.circular(999),
- border: Border.all(color: colors.border),
- ),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- time,
- style: theme.textTheme.labelLarge?.copyWith(
- color: colors.ink,
- fontSize: 16,
- fontFeatures: const [FontFeature.tabularFigures()],
- ),
- ),
- const SizedBox(width: 14),
- _StripMetric(
- iconAsset: 'assets/icons/gauge.svg',
- text: speed == null ? '-- km/h' : '${speed.round()} km/h',
- available: speed != null,
- ),
- const SizedBox(width: 14),
- _StripMetric(
- iconAsset: 'assets/icons/thermometer.svg',
- text: temperature == null ? '--°C' : '${temperature.round()}°C',
- available: temperature != null,
- ),
- const SizedBox(width: 10),
- Pressable(
- onTap: () =>
- Navigator.of(context).popUntil((route) => route.isFirst),
- semanticLabel: 'Go to home',
- pressedScale: 0.92,
- child: Container(
- width: 42,
- height: 42,
- decoration: BoxDecoration(
- color: colors.surfaceStrong,
- shape: BoxShape.circle,
- border: Border.all(color: colors.border),
- ),
- alignment: Alignment.center,
- child: AppIcon(
- 'assets/icons/home.svg',
- size: 21,
- color: colors.ink,
- ),
- ),
- ),
- ],
- ),
- );
- }
- }
- class _StripMetric extends StatelessWidget {
- const _StripMetric({
- required this.iconAsset,
- required this.text,
- required this.available,
- });
- final String iconAsset;
- final String text;
- final bool available;
- @override
- Widget build(BuildContext context) {
- final colors = context.colors;
- final theme = Theme.of(context);
- return Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- AppIcon(
- iconAsset,
- size: 18,
- color: available ? colors.inkMuted : colors.inkFaint,
- ),
- const SizedBox(width: 6),
- Text(
- text,
- style: theme.textTheme.labelLarge?.copyWith(
- color: available ? colors.ink : colors.inkFaint,
- fontFeatures: const [FontFeature.tabularFigures()],
- ),
- ),
- ],
- );
- }
- }
|