Commit cb00631e by Dmitriy Stepanets

- Finished wind widget

- Widgets UI fixes
parent 24ea9f89
......@@ -183,6 +183,7 @@
CDE2BF252609D9140085C930 /* ForecastWindButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE2BF242609D9140085C930 /* ForecastWindButton.swift */; };
CDEE8AD725DA882200C289DE /* ForecastPeriodButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEE8AD625DA882200C289DE /* ForecastPeriodButton.swift */; };
CDF63D29266779D8003DE569 /* AdLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF63D28266779D8003DE569 /* AdLogger.swift */; };
CDF6E87726A8329D004A9DBD /* WindWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF6E87626A8329D004A9DBD /* WindWidget.swift */; };
CDF8F12A262089A200DB384A /* MapTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF8F129262089A200DB384A /* MapTimeView.swift */; };
CDF8F12D26208E7B00DB384A /* MapCurrentTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF8F12C26208E7B00DB384A /* MapCurrentTimeView.swift */; };
CDF9BF8E26133D050037847D /* LocationSearchCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF9BF8D26133D050037847D /* LocationSearchCoordinator.swift */; };
......@@ -496,6 +497,7 @@
CDEF70E2266E10B600BA40D6 /* OneWeatherCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OneWeatherCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CDF1F9342668D09C004F5D61 /* OneWeatherCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OneWeatherCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CDF63D28266779D8003DE569 /* AdLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdLogger.swift; sourceTree = "<group>"; };
CDF6E87626A8329D004A9DBD /* WindWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindWidget.swift; sourceTree = "<group>"; };
CDF8F129262089A200DB384A /* MapTimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTimeView.swift; sourceTree = "<group>"; };
CDF8F12C26208E7B00DB384A /* MapCurrentTimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapCurrentTimeView.swift; sourceTree = "<group>"; };
CDF9BF8D26133D050037847D /* LocationSearchCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSearchCoordinator.swift; sourceTree = "<group>"; };
......@@ -1323,6 +1325,7 @@
children = (
CD1B713F2660F95000916E71 /* TemperatureWidget.swift */,
CD58528F26A01F0E00D61021 /* PrecipitationWidget.swift */,
CDF6E87626A8329D004A9DBD /* WindWidget.swift */,
);
path = Widgets;
sourceTree = "<group>";
......@@ -1954,6 +1957,7 @@
CD5293E1266A4258009547C8 /* AppFont.swift in Sources */,
CDA02A1926A6F92F00A8F2F6 /* WeatherLocationMock.swift in Sources */,
CD5293DF266A235F009547C8 /* ForecastWidgetViewModel.swift in Sources */,
CDF6E87726A8329D004A9DBD /* WindWidget.swift in Sources */,
CD5293D8266908DB009547C8 /* WidgetPlaceholderView.swift in Sources */,
CD5293EA266A564E009547C8 /* ThemeProtocol.swift in Sources */,
CD1B71402660F95000916E71 /* TemperatureWidget.swift in Sources */,
......
......@@ -289,4 +289,6 @@
"widget.temperature.description" = "";
"widget.precipitation.title" = "Precipitation Forecast";
"widget.precipitation.description" = "";
"widget.wind.title" = "Wind Forecast";
"widget.wind.description" = "";
"widget.lastUpdatedTemplate" = "Last updated #LAST_UPDATED ago.";
......@@ -15,10 +15,12 @@ enum PromotionWidgetType {
case temperatureMedium
case temperatureLarge
case precipitationMedium
case windMedium
case windLarge
var widgetHeight: Int {
switch self {
case .temperatureLarge:
case .temperatureLarge, .windLarge:
return 376
default:
return 169
......@@ -41,6 +43,10 @@ class PromotionWidgetViewWrapper: UIView {
widgetController = UIHostingController(rootView: LargeTemperatureWidgetView(widgetViewModel: nil))
case .precipitationMedium:
widgetController = UIHostingController(rootView: MediumPrecipitationWidgetView(widgetViewModel: nil))
case .windMedium:
widgetController = UIHostingController(rootView: MediumWindWidgetView(widgetViewModel: nil))
case .windLarge:
widgetController = UIHostingController(rootView: LargeWindWidgetView(widgetViewModel: nil))
}
self.widgetType = widgetType
......
......@@ -199,6 +199,8 @@ private extension WidgetPromotionController {
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .temperatureMedium))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .temperatureLarge))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .precipitationMedium))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .windMedium))
stackView.addArrangedSubview(PromotionWidgetViewWrapper(widgetType: .windLarge))
scrollView.addSubview(stackView)
stackView.snp.makeConstraints { make in
......
......@@ -20,6 +20,7 @@
CD4319FA26A00E090019A232 /* WidgetTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4319F926A00E090019A232 /* WidgetTopView.swift */; };
CD4319FC26A014CF0019A232 /* MediumPrecipitationWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4319FB26A014CF0019A232 /* MediumPrecipitationWidgetView.swift */; };
CD50556126983C2F006776AB /* CubicCurveAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD50556026983C2E006776AB /* CubicCurveAlgorithm.swift */; };
CD55516126A8195B00C0796C /* MediumWindWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD55516026A8195B00C0796C /* MediumWindWidgetView.swift */; };
CD7D3161268EEF49000D01FA /* CityNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7D315F268EEF48000D01FA /* CityNameView.swift */; };
CD7D3162268EEF49000D01FA /* HighLowTemperatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7D3160268EEF49000D01FA /* HighLowTemperatureView.swift */; };
CD7D3164268EEF56000D01FA /* SmallTemperatureWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7D3163268EEF56000D01FA /* SmallTemperatureWidgetView.swift */; };
......@@ -38,6 +39,7 @@
CDBF6D08269887A800715981 /* LargeTemperatureWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDBF6D07269887A800715981 /* LargeTemperatureWidgetView.swift */; };
CDC3F85A26946D0700AAE3BF /* HourlyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC3F85926946D0700AAE3BF /* HourlyView.swift */; };
CDC3F85C269471C900AAE3BF /* SF-Pro-Display-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = CDC3F85B269471C900AAE3BF /* SF-Pro-Display-Bold.otf */; };
CDF969A126A848580099C3C4 /* LargeWindWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF969A026A848580099C3C4 /* LargeWindWidgetView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -70,6 +72,7 @@
CD4319F926A00E090019A232 /* WidgetTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetTopView.swift; sourceTree = "<group>"; };
CD4319FB26A014CF0019A232 /* MediumPrecipitationWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumPrecipitationWidgetView.swift; sourceTree = "<group>"; };
CD50556026983C2E006776AB /* CubicCurveAlgorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CubicCurveAlgorithm.swift; sourceTree = "<group>"; };
CD55516026A8195B00C0796C /* MediumWindWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediumWindWidgetView.swift; sourceTree = "<group>"; };
CD6F063D269854A7002A99C2 /* BezierKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BezierKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CD7D315F268EEF48000D01FA /* CityNameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CityNameView.swift; sourceTree = "<group>"; };
CD7D3160268EEF49000D01FA /* HighLowTemperatureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighLowTemperatureView.swift; sourceTree = "<group>"; };
......@@ -90,6 +93,7 @@
CDBF6D07269887A800715981 /* LargeTemperatureWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeTemperatureWidgetView.swift; sourceTree = "<group>"; };
CDC3F85926946D0700AAE3BF /* HourlyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HourlyView.swift; sourceTree = "<group>"; };
CDC3F85B269471C900AAE3BF /* SF-Pro-Display-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Pro-Display-Bold.otf"; sourceTree = "<group>"; };
CDF969A026A848580099C3C4 /* LargeWindWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeWindWidgetView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -178,6 +182,7 @@
CD259C12268DE1F7008D205E /* Widgets */ = {
isa = PBXGroup;
children = (
CD55515F26A8192500C0796C /* Wind */,
CD4319F826A00DB70019A232 /* Precipitation */,
CD4319F726A00DAB0019A232 /* Temperature */,
CDF2CF7026982DD6005EF42E /* Helpers */,
......@@ -205,6 +210,15 @@
path = Precipitation;
sourceTree = "<group>";
};
CD55515F26A8192500C0796C /* Wind */ = {
isa = PBXGroup;
children = (
CD55516026A8195B00C0796C /* MediumWindWidgetView.swift */,
CDF969A026A848580099C3C4 /* LargeWindWidgetView.swift */,
);
path = Wind;
sourceTree = "<group>";
};
CD7D315E268EEF37000D01FA /* SharedViews */ = {
isa = PBXGroup;
children = (
......@@ -389,6 +403,7 @@
CD7D3161268EEF49000D01FA /* CityNameView.swift in Sources */,
CD7D3164268EEF56000D01FA /* SmallTemperatureWidgetView.swift in Sources */,
CD1BF3B4269829CC00F60E2E /* EdgeInsets+Zero.swift in Sources */,
CD55516126A8195B00C0796C /* MediumWindWidgetView.swift in Sources */,
CD3C83C326933ABD0087A225 /* MediumTemperatureWidgetView.swift in Sources */,
CD7D3168268EF167000D01FA /* UIFont+Font.swift in Sources */,
CD7D3187268F1F2E000D01FA /* UIImage+Resize.swift in Sources */,
......@@ -401,6 +416,7 @@
CDBF6D08269887A800715981 /* LargeTemperatureWidgetView.swift in Sources */,
CDC3F85A26946D0700AAE3BF /* HourlyView.swift in Sources */,
CD7D3176268EF8A9000D01FA /* WidgetFont.swift in Sources */,
CDF969A126A848580099C3C4 /* LargeWindWidgetView.swift in Sources */,
CD7D3169268EF167000D01FA /* UIColor+Color.swift in Sources */,
CD2E07BD269C54B5001CBF40 /* WidgetColor.swift in Sources */,
);
......
{
"images" : [
{
"filename" : "wind_direction.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
......@@ -29,6 +29,7 @@ public struct MediumPrecipitationWidgetView: View {
}
.padding(.bottom, 10)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding([.leading, .trailing], 10)
.background(WidgetColor.Name("PrimaryBackground"))
}
......
......@@ -11,6 +11,7 @@ import SwiftUI
enum HourlyViewType {
case temperature
case precipitation
case wind
}
@available(iOS 14, *)
......@@ -20,28 +21,98 @@ struct HourlyView: View {
private let hourlyWeather: WidgetHourlyWeather
private let viewType: HourlyViewType
//Computed
private var topText: String {
switch viewType {
case .temperature:
return hourlyWeather.tempLocalized
case .precipitation:
return "\(hourlyWeather.precipitationPercent)%"
case .wind:
return hourlyWeather.windDirection.uppercased() + "\n" + hourlyWeather.windSpeedLocalized.uppercased()
}
}
private var topLabelFontSize: CGFloat {
switch viewType {
case .temperature, .precipitation:
return 16
case .wind:
return 12
}
}
private var image: Image? {
switch viewType {
case .temperature:
return nil
case .precipitation:
let imageName = hourlyWeather.precipitationPercent > 0 ? "precipitation_full" : "precipitation_zero"
guard let uiImage = UIImage(named: imageName, in: OneWeatherUI.frameworkBundle, compatibleWith: nil) else {
return Image("")
}
return Image(uiImage: uiImage.scalePreservingAspectRatio(targetSize: .init(width: 18, height: 18)))
case .wind:
guard let uiImage = UIImage(named: "wind_direction", in: OneWeatherUI.frameworkBundle, compatibleWith: nil) else {
return Image("")
}
return Image(uiImage: uiImage.scalePreservingAspectRatio(targetSize: .init(width: 18, height: 18)))
}
}
private var rotationAngle: Angle {
switch viewType {
case .temperature, .precipitation:
return .zero
case .wind:
return Angle(degrees: Double(hourlyWeather.windDegrees))
}
}
public init(hourlyWeather: WidgetHourlyWeather, viewType: HourlyViewType) {
self.hourlyWeather = hourlyWeather
self.viewType = viewType
}
var body: some View {
VStack {
Text(viewType == .temperature ? hourlyWeather.tempLocalized : "\(hourlyWeather.precipitationPercent)%")
VStack(spacing: 0) {
Text(topText)
.lineLimit(nil)
.multilineTextAlignment(.center)
.foregroundColor(WidgetColor.Name("HourlyText"))
.font(hourlyWeather.isSelected ? WidgetFont.SFProDisplay.bold(size: 16).font
: WidgetFont.SFProDisplay.regular(size: 16).font)
.font(hourlyWeather.isSelected ? WidgetFont.SFProDisplay.bold(size: topLabelFontSize).font
: WidgetFont.SFProDisplay.regular(size: topLabelFontSize).font)
.padding(.top, 8)
Spacer()
if viewType == .precipitation {
precipitationImage()
if viewType == .wind {
Spacer()
.frame(height: 4)
}
else {
Spacer()
}
if let typeImage = self.image {
typeImage
.frame(width: 18, height: 18)
.rotationEffect(rotationAngle)
if viewType == .wind {
Spacer()
.frame(height: 3)
}
else {
Spacer()
}
}
Text(hourlyWeather.dateString)
.foregroundColor(WidgetColor.Name("HourlyText"))
.font(hourlyWeather.isSelected ? WidgetFont.SFProDisplay.bold(size: 12).font
: WidgetFont.SFProDisplay.regular(size: 12).font)
.padding(.bottom, 8)
.padding(.bottom, 5)
}
.frame(width: 70)
.modifier(Background(isSelected: hourlyWeather.isSelected))
......@@ -50,16 +121,6 @@ struct HourlyView: View {
.modifier(Shadow(isSelected: hourlyWeather.isSelected))
.modifier(Border(isSelected: hourlyWeather.isSelected))
}
@available(iOS 14, *)
private func precipitationImage() -> Image {
let imageName = hourlyWeather.precipitationPercent > 0 ? "precipitation_full" : "precipitation_zero"
guard let uiImage = UIImage(named: imageName, in: OneWeatherUI.frameworkBundle, compatibleWith: nil) else {
return Image("")
}
return Image(uiImage: uiImage.scalePreservingAspectRatio(targetSize: .init(width: 18, height: 18)))
}
}
@available(iOS 14, *)
......
......@@ -57,15 +57,17 @@ struct WidgetTopView: View {
}
.frame(height: 35)
HStack(alignment: .top) {
Text(widgetViewModel.smartText)
.lineLimit(2)
.font(WidgetFont.SFProDisplay.regular(size: 12).font)
Spacer()
if widgetViewModel.showLastTimeUpdated {
Text(widgetViewModel.lastTimeUpdatedText)
.font(WidgetFont.SFProDisplay.regular(size: 9).font)
if style == .medium {
HStack(alignment: .top) {
Text(widgetViewModel.smartText)
.lineLimit(2)
.font(WidgetFont.SFProDisplay.regular(size: 12).font)
Spacer()
if widgetViewModel.showLastTimeUpdated {
Text(widgetViewModel.lastTimeUpdatedText)
.font(WidgetFont.SFProDisplay.regular(size: 9).font)
}
}
}
}
......
......@@ -48,24 +48,30 @@ public struct LargeTemperatureWidgetView: View {
HStack {
Text(daily.dateString)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
weatherDayImage(uiImage: daily.weatherIcon)
Spacer()
.frame(width: 52)
Text(daily.minTemp)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
.frame(width: 52)
Text(daily.maxTemp)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
.frame(width: 28)
HStack {
Spacer()
.frame(width: 16)
weatherDayImage(uiImage: daily.weatherIcon)
Spacer()
Text(daily.minTemp)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
Text(daily.maxTemp)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
.frame(width: 10)
}
.frame(width: 200)
}
}
}
.padding([.top, .bottom], 20)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding([.leading, .trailing], 10)
.background(WidgetColor.Name("PrimaryBackground"))
}
......
......@@ -33,7 +33,7 @@ public struct MediumTemperatureWidgetView: View {
@available(iOS 14, *)
public struct MediumTemperatureWidgetView_Preview: PreviewProvider {
public static var previews: some View {
MediumTemperatureWidgetView(widgetViewModel: WidgetViewModelMock())
MediumTemperatureWidgetView(widgetViewModel: nil)
.previewDevice("iPhone 11")
.preferredColorScheme(.dark)
.frame(width: 338, height: 158)
......
......@@ -7,9 +7,44 @@
import UIKit
private enum Day: String, CaseIterable {
case monday = "monday"
case tuesday = "tuesday"
case wednesday = "wednesday"
case thursday = "thursday"
case friday = "friday"
case saturday = "saturday"
case sunday = "sunday"
static func day(by number: Int) -> Self {
switch number {
case 1:
return .monday
case 2:
return .tuesday
case 3:
return .wednesday
case 4:
return .thursday
case 5:
return .friday
case 6:
return .saturday
case 7:
return .sunday
default:
return .monday
}
}
}
@available(iOS 14, *)
struct WidgetViewModelMock: WidgetViewModel {
private class OneWeatherUIClass {}
static private var randomTemp: Double {
Double((68...90).randomElement() ?? 68)
}
let showLastTimeUpdated = true
let lastTimeUpdatedText = "Last updated 2h ago."
let cityName = "New York"
......@@ -24,14 +59,14 @@ struct WidgetViewModelMock: WidgetViewModel {
let hourlyWeather: [WidgetHourlyWeather] = {
var array = [WidgetHourlyWeather]()
for index in 0..<4 {
let hourly = WidgetHourlyWeather(dateString: "11 AM",
temp: 17 + 2 * Double(index),
tempLocalized: "\(17 + 2 * index)°",
windSpeed: 15,
windSpeedLocalized: "8m/s",
let hourly = WidgetHourlyWeather(dateString: "\(9 + index) AM",
temp: randomTemp,
tempLocalized: "\(Int(randomTemp))°",
windSpeed: Double((0...15).randomElement() ?? 0),
windSpeedLocalized: "\(Int((0...15).randomElement() ?? 0))m/s",
windDirection: "SSE",
windDegrees: 25,
precipitationPercent: 12,
windDegrees: 45,
precipitationPercent: (0...100).randomElement() ?? 0,
isSelected: index == 0)
array.append(hourly)
}
......@@ -41,7 +76,7 @@ struct WidgetViewModelMock: WidgetViewModel {
let dailyWather: [WidgetDailyWeather] = {
var array = [WidgetDailyWeather]()
for index in 0..<4 {
let daily = WidgetDailyWeather(dateString: "19, Monday",
let daily = WidgetDailyWeather(dateString: "\(10 + index), \(Day.day(by: index + 1).rawValue.capitalized)",
isToday: false,
minTemp: "\(10 + 2 * index)°",
maxTemp: "\(22 + 2 * index)°",
......
//
// LargeWindWidgetView.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 21.07.2021.
//
import SwiftUI
@available(iOS 14, *)
public struct LargeWindWidgetView: View {
//Public
let widgetViewModel: WidgetViewModel
//Private
@Environment(\.colorScheme) private var colorScheme
public init(widgetViewModel: WidgetViewModel?) {
OneWeatherUI.loadFonts
self.widgetViewModel = widgetViewModel ?? WidgetViewModelMock()
}
public var body: some View {
VStack(alignment: .center, spacing: 0) {
HStack {
CityNameView(cityName: widgetViewModel.cityName,
isDeviceLocation: widgetViewModel.isDeviceLocation)
.padding(.top, 12)
Spacer()
}
WidgetTopView(widgetViewModel: widgetViewModel,
style: .large)
.padding(.top, 4)
HStack(spacing: 10) {
ForEach(0 ..< widgetViewModel.hourlyWeather.count) { index in
HourlyView(hourlyWeather: widgetViewModel.hourlyWeather[index],
viewType: .wind)
.frame(maxWidth: 70)
}
}
.padding(.top, 16)
HStack {
Text("Next few Days")
.font(WidgetFont.SFProDisplay.regular(size: 12).font)
VStack {
Divider()
.background(WidgetColor.Name("Divider"))
.padding(.top, 8)
}
}
.padding(.top, 17)
VStack {
ForEach(0..<min(4, widgetViewModel.dailyWather.count)) { index in
let daily = widgetViewModel.dailyWather[index]
HStack {
Text(daily.dateString)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
HStack {
Spacer()
.frame(width: 16)
weatherDayImage(uiImage: daily.weatherIcon)
Spacer()
Text(daily.minTemp)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
Text(daily.maxTemp)
.font(WidgetFont.SFProDisplay.thin(size: 14).font)
Spacer()
.frame(width: 10)
}
.frame(width: 200)
}
}
}
.padding([.top, .bottom], 20)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding([.leading, .trailing], 10)
.background(WidgetColor.Name("PrimaryBackground"))
}
func weatherDayImage(uiImage: UIImage) -> Image {
return Image(uiImage: uiImage.scalePreservingAspectRatio(targetSize: .init(width: 20, height: 20)))
}
}
@available(iOS 14, *)
public struct LargeWindWidgetView_Preview: PreviewProvider {
public static var previews: some View {
LargeWindWidgetView(widgetViewModel: WidgetViewModelMock())
.previewDevice("iPhone 11")
.preferredColorScheme(.dark)
.frame(width: 338, height: 380)
}
}
//
// MediumWindWidgetView.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 21.07.2021.
//
import SwiftUI
@available(iOS 14, *)
public struct MediumWindWidgetView: View {
let widgetViewModel: WidgetViewModel
public init(widgetViewModel: WidgetViewModel?) {
OneWeatherUI.loadFonts
self.widgetViewModel = widgetViewModel ?? WidgetViewModelMock()
}
public var body: some View {
VStack(alignment: .center) {
WidgetTopView(widgetViewModel: widgetViewModel, style: .medium)
.padding(.top, 12)
HStack(spacing: 10) {
ForEach(0 ..< widgetViewModel.hourlyWeather.count) { index in
HourlyView(hourlyWeather: widgetViewModel.hourlyWeather[index],
viewType: .wind)
.frame(maxWidth: 70)
}
}
.padding(.bottom, 2)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding([.leading, .trailing], 10)
.background(WidgetColor.Name("PrimaryBackground"))
}
}
@available(iOS 14, *)
struct MediumWindWidgetView_Preview: PreviewProvider {
public static var previews: some View {
MediumWindWidgetView(widgetViewModel: WidgetViewModelMock())
.previewDevice("iPhone 11")
.preferredColorScheme(.dark)
.frame(width: 338, height: 158)
}
}
......@@ -43,8 +43,8 @@ struct WeatherLocationMock {
dewPoint: .init(value: 69 + Double(index) * 2, unit: .fahrenheit),
apparentTemp: .init(value: 65 + Double(index) * 2, unit: .fahrenheit),
windSpeed: .init(value: Double(8 + index), unit: .metersPerSecond),
windDirection: .northNorthEast,
precipitationProbability: 55,
windDirection: WindDirection.allCases.randomElement(),
precipitationProbability: (0...100).randomElement(),
humidity: 80)
array.append(hourly)
}
......
......@@ -12,5 +12,6 @@ struct OneWeatherWidgets: WidgetBundle {
var body: some Widget {
TemperatureWidget()
PrecipitationWidget()
WindWidget()
}
}
......@@ -65,7 +65,7 @@ struct ForecastWidgetViewModel: WidgetViewModel {
tempLocalized: hourly.temp?.settingsConverted.shortString ?? "",
windSpeed: hourly.windSpeed?.settingsConvertedValue ?? 0,
windSpeedLocalized: hourly.windSpeed?.settingsConverted.shortString ?? "",
windDirection: hourly.windDirection?.fullLocalized ?? "",
windDirection: hourly.windDirection?.rawValue ?? "",
windDegrees: hourly.windDirection?.degrees ?? 0,
precipitationPercent: Int(hourly.precipitationProbability ?? 0),
isSelected: isSelected)
......
......@@ -26,3 +26,12 @@ struct PrecipitationWidget: Widget {
.supportedFamilies([.systemMedium])
}
}
struct PrecipitationWidget_Preview: PreviewProvider {
public static var previews: some View {
MediumPrecipitationWidgetView(widgetViewModel: ForecastWidgetViewModel(location: WeatherLocationMock().location))
.preferredColorScheme(.dark)
.previewDevice("iPhone 11")
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
//
// WindWidget.swift
// OneWeatherWidgetExtension
//
// Created by Dmitry Stepanets on 21.07.2021.
//
import WidgetKit
import SwiftUI
import OneWeatherUI
import Localize_Swift
struct WindWidget: Widget {
private let kind = "com.onelouder.oneweather.widget.wind"
var body: some WidgetConfiguration {
// We currently display selectedLocation, so it's not really configurable,
// but we'll probably need to switch to an IntentConfiguration at some point.
StaticConfiguration(kind: kind,
provider: WeatherProvider()
) { weatherEntry in
WidgetView(entry: weatherEntry)
}
.configurationDisplayName("widget.wind.title".localized())
.description("widget.wind.description".localized())
.supportedFamilies([.systemMedium, .systemLarge])
}
}
private struct WidgetView: View {
@Environment(\.widgetFamily) private var widgetSize
let entry: WeatherEntry
var body: some View {
let viewModel = ForecastWidgetViewModel(location: entry.location)
switch widgetSize {
case .systemMedium:
MediumWindWidgetView(widgetViewModel: viewModel)
case .systemLarge:
LargeWindWidgetView(widgetViewModel: viewModel)
default:
MediumWindWidgetView(widgetViewModel: viewModel)
}
}
}
struct WindWidget_Preview: PreviewProvider {
public static var previews: some View {
WidgetView(entry: WeatherEntry())
.preferredColorScheme(.dark)
.previewDevice("iPhone 11")
.previewContext(WidgetPreviewContext(family: .systemLarge))
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment