diff --git a/lib/screens/journal/journal_screen.dart b/lib/screens/journal/journal_screen.dart index c1dab35..be83d64 100644 --- a/lib/screens/journal/journal_screen.dart +++ b/lib/screens/journal/journal_screen.dart @@ -10,7 +10,6 @@ import '../../providers/journal_provider.dart'; import '../../providers/voice_provider.dart'; import '../../widgets/chat_message_bubble.dart'; import '../../widgets/voice_mic_button.dart'; -import '../../widgets/weather_card.dart'; import 'journal_history_screen.dart'; class JournalScreen extends ConsumerStatefulWidget { @@ -366,9 +365,10 @@ class _JournalScreenState extends ConsumerState } } -/// Renders a single journal message. For the daily-prep assistant message, -/// also renders a WeatherCard above the bubble (weather lives in the -/// nested metadata.sections.weather payload). +/// Renders a single journal message. The daily-prep prose itself already +/// covers weather ("Weather at home will reach a high of 15.9° ..."), so +/// the journal screen leaves rendering to the message bubble — no separate +/// weather card on top. class _JournalMessageItem extends StatelessWidget { final Message message; @@ -376,33 +376,7 @@ class _JournalMessageItem extends StatelessWidget { @override Widget build(BuildContext context) { - final meta = message.metadata; - final isAssistant = message.role == MessageRole.assistant; - final isPrep = isAssistant && - meta != null && - meta['kind'] == 'daily_prep'; - - Map? weatherData; - if (isPrep) { - // The journal prep stores its structured data under metadata.sections. - final sections = meta['sections'] as Map?; - final weather = sections?['weather']; - if (weather is List && weather.isNotEmpty) { - // Show the first location's weather card. The widget expects a - // single location dict; we pass the first one through. - weatherData = weather.first as Map?; - } else if (weather is Map) { - weatherData = weather as Map; - } - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (weatherData != null) WeatherCard(weather: weatherData), - ChatMessageBubble(message: message), - ], - ); + return ChatMessageBubble(message: message); } } diff --git a/lib/widgets/weather_card.dart b/lib/widgets/weather_card.dart deleted file mode 100644 index 93cf8a8..0000000 --- a/lib/widgets/weather_card.dart +++ /dev/null @@ -1,185 +0,0 @@ -import 'package:flutter/material.dart'; - -class WeatherCard extends StatelessWidget { - final Map? weather; - - const WeatherCard({super.key, required this.weather}); - - @override - Widget build(BuildContext context) { - final scheme = Theme.of(context).colorScheme; - - if (weather == null) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), - decoration: BoxDecoration( - color: scheme.surfaceContainerHighest, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: scheme.outlineVariant), - ), - child: Text( - 'Weather data unavailable — will retry at next slot.', - style: TextStyle( - color: scheme.onSurfaceVariant, - fontStyle: FontStyle.italic, - fontSize: 13, - ), - ), - ); - } - - final w = weather!; - final location = w['location'] as String? ?? ''; - final currentTemp = w['current_temp']; - final condition = w['condition'] as String? ?? ''; - final todayHigh = w['today_high']; - final todayLow = w['today_low']; - final yesterdayHigh = w['yesterday_high']; - final fetchedAt = w['fetched_at'] as String?; - final forecast = (w['forecast'] as List? ?? []) - .cast>(); - - String? tempDelta; - if (todayHigh != null && yesterdayHigh != null) { - final diff = (todayHigh as num) - (yesterdayHigh as num); - if (diff.abs() < 1) { - tempDelta = 'Same as yesterday'; - } else { - final dir = diff > 0 ? 'warmer' : 'cooler'; - tempDelta = '${diff.abs().round()}° $dir than yesterday'; - } - } - - String? fetchedLabel; - if (fetchedAt != null) { - try { - final dt = DateTime.parse(fetchedAt).toLocal(); - final h = dt.hour % 12 == 0 ? 12 : dt.hour % 12; - final m = dt.minute.toString().padLeft(2, '0'); - final period = dt.hour < 12 ? 'AM' : 'PM'; - fetchedLabel = '$h:$m $period'; - } catch (_) {} - } - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(14), - decoration: BoxDecoration( - color: scheme.surfaceContainerHighest, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: scheme.outlineVariant), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header: location + fetched time - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - location, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: scheme.onSurface, - ), - ), - if (fetchedLabel != null) - Text( - 'as of $fetchedLabel', - style: TextStyle( - fontSize: 12, - color: scheme.onSurfaceVariant, - ), - ), - ], - ), - const SizedBox(height: 8), - // Current temp + condition - Row( - crossAxisAlignment: CrossAxisAlignment.baseline, - textBaseline: TextBaseline.alphabetic, - children: [ - Text( - '$currentTemp°', - style: TextStyle( - fontSize: 36, - fontWeight: FontWeight.w700, - color: scheme.onSurface, - height: 1, - ), - ), - const SizedBox(width: 10), - Text( - condition, - style: TextStyle( - fontSize: 14, - color: scheme.onSurfaceVariant, - ), - ), - ], - ), - // Today high/low + delta - if (todayHigh != null) ...[ - const SizedBox(height: 8), - Text( - 'Today: $todayHigh° / $todayLow°' - '${tempDelta != null ? ' · $tempDelta' : ''}', - style: TextStyle(fontSize: 13, color: scheme.onSurfaceVariant), - ), - ], - // Forecast strip - if (forecast.isNotEmpty) ...[ - const SizedBox(height: 12), - const Divider(height: 1), - const SizedBox(height: 12), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - spacing: 8, - children: forecast.map((day) { - return SizedBox( - width: 64, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - day['day'] as String? ?? '', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: scheme.onSurface, - ), - ), - const SizedBox(height: 3), - Text( - day['condition'] as String? ?? '', - style: TextStyle( - fontSize: 11, - color: scheme.onSurfaceVariant, - ), - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 3), - Text( - '${day['high']}° / ${day['low']}°', - style: TextStyle( - fontSize: 12, - color: scheme.onSurface, - ), - ), - ], - ), - ); - }).toList(), - ), - ), - ], - ], - ), - ); - } -}