Преглед на файлове

fix: center now-playing title across media card

Move the now-playing row out of the right-hand control column so it spans the full card width and centers against the card. Update screenshots and bump to 0.9.1.
Krasimir Kazakov преди 1 седмица
родител
ревизия
7c3a676e96

+ 1 - 1
README.md

@@ -269,7 +269,7 @@ title, artist, progress and pause/resume were verified against a live Chrome
 MediaSession. The OBD hardware path compiles and is covered by the parser/economy
 design, but no ELM327 adapter is available on this machine; socket behavior still
 needs a car test. Release
-0.9.0 is installed on the emulator and the physical Android 17 HyperOS tablet.
+0.9.1 is installed on the emulator and the physical Android 17 HyperOS tablet.
 
 ## Troubleshooting the emulator
 

+ 3 - 1
docs/IMPLEMENTATION_PLAN.md

@@ -184,7 +184,7 @@ Android (Kotlin)
   both the ring and scroll position, resume continues.
 - [x] Settings → Media grants notification access and shows Granted.
 - [x] Settings gear is next to Wi-Fi; the grid ends with All apps.
-- [x] Release 0.9.0 installed on the emulator and physical Android 17 tablet.
+- [x] Release 0.9.1 installed on the emulator and physical Android 17 tablet.
 - [x] Screenshots in `docs/screenshots/`; README/AGENTS/plan/OBD doc updated.
 
 ## 6. Known risks and mitigations
@@ -273,3 +273,5 @@ Android (Kotlin)
   with a dim clock, and verified the 16-button layout at 1280×720. Verified the
   native window flag toggles off/on, night mode/card long-press isolation, 44 tests
   and 0.9.0 on emulator/tablet.
+- 2026-10-29: Centered the now-playing title across the whole media card instead of
+  the right-hand control column. Verified 0.9.1 on emulator/tablet.

BIN
docs/screenshots/home-1280x720.png


BIN
docs/screenshots/home-16-1024.png


BIN
docs/screenshots/home-16.png


BIN
docs/screenshots/home-now-playing.png


+ 136 - 136
lib/features/home/widgets/volume_card.dart

@@ -61,156 +61,156 @@ class _VolumeCardState extends State<VolumeCard> {
     return SurfaceCard(
       padding: EdgeInsets.all(compact ? 20 : 26),
       radius: 30,
-      child: Row(
-        crossAxisAlignment: CrossAxisAlignment.center,
+      child: Column(
+        mainAxisSize: MainAxisSize.min,
+        crossAxisAlignment: CrossAxisAlignment.stretch,
         children: [
-          Pressable(
-            onTap: widget.onPlayPause,
-            semanticLabel: widget.isMusicPlaying ? 'Pause music' : 'Play music',
-            pressedScale: 0.94,
-            child: _VolumeRing(
-              progress: widget.media.progress,
-              isPlaying: widget.isMusicPlaying,
-              size: compact ? 78 : 92,
-            ),
-          ),
-          SizedBox(width: compact ? 18 : 24),
-          Expanded(
-            child: Column(
-              mainAxisSize: MainAxisSize.min,
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                Row(
+          Row(
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              Pressable(
+                onTap: widget.onPlayPause,
+                semanticLabel: widget.isMusicPlaying
+                    ? 'Pause music'
+                    : 'Play music',
+                pressedScale: 0.94,
+                child: _VolumeRing(
+                  progress: widget.media.progress,
+                  isPlaying: widget.isMusicPlaying,
+                  size: compact ? 78 : 92,
+                ),
+              ),
+              SizedBox(width: compact ? 18 : 24),
+              Expanded(
+                child: Column(
+                  mainAxisSize: MainAxisSize.min,
+                  crossAxisAlignment: CrossAxisAlignment.start,
                   children: [
-                    Text(
-                      'Media volume',
-                      style: theme.textTheme.labelLarge?.copyWith(
-                        color: colors.inkMuted,
-                        fontSize: compact ? 12 : 13,
-                      ),
+                    Row(
+                      children: [
+                        Text(
+                          'Media volume',
+                          style: theme.textTheme.labelLarge?.copyWith(
+                            color: colors.inkMuted,
+                            fontSize: compact ? 12 : 13,
+                          ),
+                        ),
+                        const Spacer(),
+                        Text(
+                          '$_percent%',
+                          style: theme.textTheme.headlineMedium?.copyWith(
+                            fontSize: compact ? 24 : 28,
+                            fontFeatures: const [FontFeature.tabularFigures()],
+                          ),
+                        ),
+                      ],
                     ),
-                    const Spacer(),
-                    Text(
-                      '$_percent%',
-                      style: theme.textTheme.headlineMedium?.copyWith(
-                        fontSize: compact ? 24 : 28,
-                        fontFeatures: const [FontFeature.tabularFigures()],
+                    const SizedBox(height: 2),
+                    SliderTheme(
+                      data: SliderTheme.of(context).copyWith(
+                        trackHeight: compact ? 5 : 6,
+                        thumbShape: RoundSliderThumbShape(
+                          enabledThumbRadius: compact ? 9 : 10,
+                        ),
+                      ),
+                      child: Slider(
+                        value: displayValue,
+                        min: 0,
+                        max: _max.toDouble(),
+                        divisions: _max <= 30 ? _max : null,
+                        onChanged: (next) {
+                          setState(() => _dragValue = next);
+                          widget.onSetVolume(next.round());
+                        },
+                        onChangeEnd: (_) => setState(() => _dragValue = null),
+                        semanticFormatterCallback: (value) =>
+                            '${(value / _max * 100).round()} percent',
                       ),
                     ),
-                  ],
-                ),
-                const SizedBox(height: 2),
-                SliderTheme(
-                  data: SliderTheme.of(context).copyWith(
-                    trackHeight: compact ? 5 : 6,
-                    thumbShape: RoundSliderThumbShape(
-                      enabledThumbRadius: compact ? 9 : 10,
-                    ),
-                  ),
-                  child: Slider(
-                    value: displayValue,
-                    min: 0,
-                    max: _max.toDouble(),
-                    divisions: _max <= 30 ? _max : null,
-                    onChanged: (next) {
-                      setState(() => _dragValue = next);
-                      widget.onSetVolume(next.round());
-                    },
-                    onChangeEnd: (_) => setState(() => _dragValue = null),
-                    semanticFormatterCallback: (value) =>
-                        '${(value / _max * 100).round()} percent',
-                  ),
-                ),
-                SizedBox(height: compact ? 4 : 8),
-                Row(
-                  children: [
-                    _StepButton(
-                      icon: Icons.remove_rounded,
-                      semanticLabel: 'Volume down',
-                      onTap: () => widget.onSetVolume(_value - 1),
-                      compact: compact,
-                    ),
-                    SizedBox(width: compact ? 8 : 10),
-                    Expanded(
-                      child: Pressable(
-                        onTap: widget.onToggleMute,
-                        semanticLabel: _muted ? 'Unmute' : 'Mute',
-                        pressedScale: 0.97,
-                        child: Container(
-                          height: compact ? 36 : 40,
-                          decoration: BoxDecoration(
-                            color: _muted
-                                ? colors.accentSoft
-                                : colors.surfaceStrong,
-                            borderRadius: BorderRadius.circular(999),
-                            border: Border.all(
-                              color: _muted
-                                  ? colors.accent.withValues(alpha: 0.25)
-                                  : colors.border,
-                            ),
-                          ),
-                          child: Row(
-                            mainAxisAlignment: MainAxisAlignment.center,
-                            children: [
-                              AppIcon(
-                                _muted
-                                    ? 'assets/icons/volume-x.svg'
-                                    : 'assets/icons/volume-2.svg',
-                                size: compact ? 16 : 18,
-                                color: _muted ? colors.accent : colors.inkMuted,
-                              ),
-                              const SizedBox(width: 8),
-                              Text(
-                                _muted ? 'Unmute' : 'Mute',
-                                style: theme.textTheme.labelMedium?.copyWith(
+                    SizedBox(height: compact ? 4 : 8),
+                    Row(
+                      children: [
+                        _StepButton(
+                          icon: Icons.remove_rounded,
+                          semanticLabel: 'Volume down',
+                          onTap: () => widget.onSetVolume(_value - 1),
+                          compact: compact,
+                        ),
+                        SizedBox(width: compact ? 8 : 10),
+                        Expanded(
+                          child: Pressable(
+                            onTap: widget.onToggleMute,
+                            semanticLabel: _muted ? 'Unmute' : 'Mute',
+                            pressedScale: 0.97,
+                            child: Container(
+                              height: compact ? 36 : 40,
+                              decoration: BoxDecoration(
+                                color: _muted
+                                    ? colors.accentSoft
+                                    : colors.surfaceStrong,
+                                borderRadius: BorderRadius.circular(999),
+                                border: Border.all(
                                   color: _muted
-                                      ? colors.accent
-                                      : colors.inkMuted,
+                                      ? colors.accent.withValues(alpha: 0.25)
+                                      : colors.border,
                                 ),
                               ),
-                            ],
+                              child: Row(
+                                mainAxisAlignment: MainAxisAlignment.center,
+                                children: [
+                                  AppIcon(
+                                    _muted
+                                        ? 'assets/icons/volume-x.svg'
+                                        : 'assets/icons/volume-2.svg',
+                                    size: compact ? 16 : 18,
+                                    color: _muted
+                                        ? colors.accent
+                                        : colors.inkMuted,
+                                  ),
+                                  const SizedBox(width: 8),
+                                  Text(
+                                    _muted ? 'Unmute' : 'Mute',
+                                    style: theme.textTheme.labelMedium
+                                        ?.copyWith(
+                                          color: _muted
+                                              ? colors.accent
+                                              : colors.inkMuted,
+                                        ),
+                                  ),
+                                ],
+                              ),
+                            ),
                           ),
                         ),
-                      ),
-                    ),
-                    SizedBox(width: compact ? 8 : 10),
-                    _StepButton(
-                      icon: Icons.add_rounded,
-                      semanticLabel: 'Volume up',
-                      onTap: () => widget.onSetVolume(_value + 1),
-                      compact: compact,
+                        SizedBox(width: compact ? 8 : 10),
+                        _StepButton(
+                          icon: Icons.add_rounded,
+                          semanticLabel: 'Volume up',
+                          onTap: () => widget.onSetVolume(_value + 1),
+                          compact: compact,
+                        ),
+                      ],
                     ),
                   ],
                 ),
-                SizedBox(height: compact ? 8 : 10),
-                SizedBox(
-                  height: compact ? 18 : 20,
-                  child: Row(
-                    children: [
-                      Icon(
-                        Icons.music_note_rounded,
-                        size: compact ? 14 : 15,
-                        color: colors.inkMuted,
-                      ),
-                      const SizedBox(width: 6),
-                      Expanded(
-                        child: MarqueeText(
-                          text: _nowPlayingLabel,
-                          animate:
-                              widget.isMusicPlaying &&
-                              widget.media.displayTitle != null,
-                          style: theme.textTheme.bodySmall?.copyWith(
-                            color: widget.media.displayTitle == null
-                                ? colors.inkMuted
-                                : colors.ink,
-                            fontSize: compact ? 11 : 12,
-                          ),
-                        ),
-                      ),
-                    ],
-                  ),
+              ),
+            ],
+          ),
+          SizedBox(height: compact ? 8 : 10),
+          SizedBox(
+            height: compact ? 18 : 20,
+            child: Center(
+              child: MarqueeText(
+                text: _nowPlayingLabel,
+                animate:
+                    widget.isMusicPlaying && widget.media.displayTitle != null,
+                style: theme.textTheme.bodySmall?.copyWith(
+                  color: widget.media.displayTitle == null
+                      ? colors.inkMuted
+                      : colors.ink,
+                  fontSize: compact ? 11 : 12,
                 ),
-              ],
+              ),
             ),
           ),
         ],

+ 1 - 1
lib/features/settings/settings_screen.dart

@@ -334,7 +334,7 @@ class SettingsScreen extends StatelessWidget {
                     const SizedBox(height: 28),
                     Center(
                       child: Text(
-                        'CarDash 0.9.0 · Android 10+',
+                        'CarDash 0.9.1 · Android 10+',
                         style: theme.textTheme.bodySmall?.copyWith(
                           color: colors.inkFaint,
                         ),

+ 1 - 1
pubspec.yaml

@@ -1,7 +1,7 @@
 name: cardash_launcher
 description: "CarDash — a calm, configurable Android car dashboard launcher."
 publish_to: "none"
-version: 0.9.0+9
+version: 0.9.1+10
 
 environment:
   sdk: ^3.13.7