const std = @import("std"); const types = @import("../weather/types.zig"); const utils = @import("utils.zig"); pub fn render(writer: *std.Io.Writer, weather: types.WeatherData, use_imperial: bool) !void { // Header with location try writer.print("Weather report: {s}\n\n", .{weather.locationDisplayName()}); // Current conditions try writer.print(" Current conditions\n", .{}); try writer.print(" {s}\n", .{weather.current.condition}); try writer.writeAll(" 🌡️ "); if (use_imperial) { try writer.print("{d:.1}°F\n", .{weather.current.tempFahrenheit()}); } else { try writer.print("{d:.1}°C ({d:.1}°F)\n", .{ weather.current.temp_c, weather.current.tempFahrenheit() }); } try writer.writeAll(" 💧 "); try writer.print("{d}%\n", .{weather.current.humidity}); try writer.writeAll(" 🌬️ "); if (use_imperial) { const wind_mph = weather.current.windMph(); try writer.print("{d:.1} mph {s}\n", .{ wind_mph, utils.degreeToDirection(weather.current.wind_deg) }); } else { try writer.print("{d:.1} km/h {s}\n", .{ weather.current.wind_kph, utils.degreeToDirection(weather.current.wind_deg) }); } try writer.writeAll(" 🔽 "); if (use_imperial) { const pressure_inhg = weather.current.pressure_mb * 0.02953; try writer.print("{d:.2} inHg\n", .{pressure_inhg}); } else { try writer.print("{d:.1} hPa\n", .{weather.current.pressure_mb}); } try writer.writeAll(" 💦 "); if (use_imperial) { const precip_in = weather.current.precip_mm * 0.0393701; try writer.print("{d:.2} in\n\n", .{precip_in}); } else { try writer.print("{d:.1} mm\n\n", .{weather.current.precip_mm}); } // Forecast if (weather.forecast.len > 0) { try writer.print(" Forecast\n", .{}); for (weather.forecast) |day| { try writer.print(" {}-{:0>2}-{:0>2}: {s}\n", .{ day.date.year, @intFromEnum(day.date.month), day.date.day, day.condition }); try writer.writeAll(" ↑ "); if (use_imperial) { try writer.print("{d:.1}°F ", .{day.maxTempFahrenheit()}); } else { try writer.print("{d:.1}°C ", .{day.max_temp_c}); } try writer.writeAll("↓ "); if (use_imperial) { try writer.print("{d:.1}°F\n", .{day.minTempFahrenheit()}); } else { try writer.print("{d:.1}°C\n", .{day.min_temp_c}); } } } } test "render v2 format" { const allocator = std.testing.allocator; const weather = types.WeatherData{ .location = "Munich", .coords = .{ .latitude = 0, .longitude = 0 }, .current = .{ .temp_c = 12.0, .feels_like_c = 12.0, .condition = "Overcast", .weather_code = .clouds_overcast, .humidity = 80, .wind_kph = 15.0, .wind_deg = 315.0, .pressure_mb = 1015.0, .precip_mm = 0.5, .visibility_km = null, }, .forecast = &[_]types.ForecastDay{}, .allocator = allocator, }; var output_buf: [2048]u8 = undefined; var writer = std.Io.Writer.fixed(&output_buf); try render(&writer, weather, false); const output = output_buf[0..writer.end]; try std.testing.expect(output.len > 0); try std.testing.expect(std.mem.indexOf(u8, output, "Munich") != null); try std.testing.expect(std.mem.indexOf(u8, output, "Current conditions") != null); try std.testing.expect(std.mem.indexOf(u8, output, "12.0°C") != null); } test "render v2 format with imperial units" { const allocator = std.testing.allocator; const weather = types.WeatherData{ .location = "Boston", .coords = .{ .latitude = 0, .longitude = 0 }, .current = .{ .temp_c = 10.0, .feels_like_c = 10.0, .condition = "Clear", .weather_code = .clear, .humidity = 65, .wind_kph = 16.0, .wind_deg = 0.0, .pressure_mb = 1013.0, .precip_mm = 0.0, .visibility_km = null, }, .forecast = &[_]types.ForecastDay{}, .allocator = allocator, }; var output_buf: [2048]u8 = undefined; var writer = std.Io.Writer.fixed(&output_buf); try render(&writer, weather, true); const output = output_buf[0..writer.end]; try std.testing.expect(std.mem.indexOf(u8, output, "50.0°F") != null); try std.testing.expect(std.mem.indexOf(u8, output, "mph") != null); try std.testing.expect(std.mem.indexOf(u8, output, "inHg") != null); }