import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:flutter/foundation.dart'; import '../config/api_config.dart'; import '../models/weather_info.dart'; import '../services/weather_service.dart'; class WeatherWidget extends StatefulWidget { const WeatherWidget({super.key}); @override State createState() => _WeatherWidgetState(); } class _WeatherWidgetState extends State { Timer? _refreshTimer; @override void initState() { super.initState(); // Refresh weather every 1 hour _refreshTimer = Timer.periodic(const Duration(hours: 1), (timer) { if (mounted) { setState(() {}); // Rebuild to trigger FutureBuilder } }); } @override void dispose() { _refreshTimer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return FutureBuilder( future: Provider.of( context, listen: false, ).fetchWeather(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const SizedBox.shrink(); } if (snapshot.hasError || !snapshot.hasData) { return const SizedBox.shrink(); } final weather = snapshot.data!; final weatherIcon = _getWeatherIcon(weather.icon); return Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), decoration: BoxDecoration( color: Colors.black.withOpacity(0.5), borderRadius: BorderRadius.circular(24), border: Border.all(color: Colors.white24, width: 1.5), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ // 1. Weather Icon (Material Icon) Icon( weatherIcon.icon, color: weatherIcon.color, size: 40, ), const SizedBox(width: 16), // 2. Temperatures Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ // Current Text( '${weather.temperature.round()}°', style: const TextStyle( fontSize: 42, // Reduced from 54 fontWeight: FontWeight.bold, color: Colors.white, height: 1.0, ), ), const SizedBox(width: 20), // Max const Text('▲', style: TextStyle(color: Colors.redAccent, fontSize: 16)), Text( '${weather.tempMax.round()}°', style: const TextStyle( fontSize: 26, fontWeight: FontWeight.bold, color: Colors.white, // Reverted to white ), ), const SizedBox(width: 12), // Min const Text('▼', style: TextStyle(color: Colors.lightBlueAccent, fontSize: 16)), Text( '${weather.tempMin.round()}°', style: const TextStyle( fontSize: 26, fontWeight: FontWeight.bold, color: Colors.white, // Reverted to white ), ), ], ), // 3. AQI if (weather.aqi > 0) ...[ const SizedBox(width: 24), Container(width: 2, height: 36, color: Colors.white24), const SizedBox(width: 24), _buildAqiBadge(weather.aqi), ], ], ), ); }, ); } // Helper to map OWM icon codes to Material Icons ({IconData icon, Color color}) _getWeatherIcon(String iconCode) { // Standard OWM codes: https://openweathermap.org/weather-conditions if (iconCode.startsWith('01')) { // Clear sky return (icon: Icons.sunny, color: Colors.amber); } else if (iconCode.startsWith('02') || iconCode.startsWith('03') || iconCode.startsWith('04')) { // Clouds return (icon: Icons.cloud, color: Colors.white70); } else if (iconCode.startsWith('09') || iconCode.startsWith('10')) { // Rain return (icon: Icons.umbrella, color: Colors.blueAccent); } else if (iconCode.startsWith('11')) { // Thunderstorm return (icon: Icons.thunderstorm, color: Colors.yellow); } else if (iconCode.startsWith('13')) { // Snow return (icon: Icons.ac_unit, color: Colors.lightBlueAccent); } else if (iconCode.startsWith('50')) { // Mist/Fog return (icon: Icons.waves, color: Colors.white54); } return (icon: Icons.wb_sunny, color: Colors.amber); // Fallback } Widget _buildAqiBadge(int aqi) { Color color; IconData icon; String label; switch (aqi) { case 1: color = Colors.blue; icon = Icons.sentiment_very_satisfied; label = "좋음"; break; case 2: color = Colors.green; icon = Icons.sentiment_satisfied; label = "보통"; break; case 3: color = Colors.yellow[700]!; icon = Icons.sentiment_neutral; label = "주의"; break; case 4: color = Colors.orange; icon = Icons.sentiment_dissatisfied; label = "나쁨"; break; case 5: color = Colors.red; icon = Icons.sentiment_very_dissatisfied; label = "매우 나쁨"; break; default: return const SizedBox.shrink(); } return Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, color: color, size: 36), const SizedBox(width: 10), Text( label, style: TextStyle(color: color, fontSize: 24, fontWeight: FontWeight.bold), ), ], ); } }