Commit 1e355fe6 by Dmitriy Stepanets

Finished UI / UX WidgetPromotionController

parent cb127a45
...@@ -111,6 +111,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -111,6 +111,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
#endif #endif
logAppLaunchEvents(launchOptions: launchOptions) logAppLaunchEvents(launchOptions: launchOptions)
if let widgetPromotionTriggerCount = Settings.shared.widgetPromotionTriggerCount {
if widgetPromotionTriggerCount >= 0 {
Settings.shared.widgetPromotionTriggerCount = widgetPromotionTriggerCount - 1
}
}
else {
if CCPAHelper.shared.isNewUser {
Settings.shared.widgetPromotionTriggerCount = 2
}
else {
Settings.shared.widgetPromotionTriggerCount = 0
}
}
return true return true
} }
......
...@@ -44,12 +44,14 @@ class TodayCoordinator: Coordinator { ...@@ -44,12 +44,14 @@ class TodayCoordinator: Coordinator {
public func openLocationsSearch() { public func openLocationsSearch() {
let searchCoordinator = LocationSearchCoordinator(parentViewController: navigationController) let searchCoordinator = LocationSearchCoordinator(parentViewController: navigationController)
searchCoordinator.parentCoordinator = self searchCoordinator.parentCoordinator = self
childCoordinators.append(searchCoordinator)
searchCoordinator.start() searchCoordinator.start()
} }
public func openNotificationsScreen() { public func openNotificationsScreen() {
let notificationsCoordinator = NotificationsCoordinator(parentViewController: navigationController) let notificationsCoordinator = NotificationsCoordinator(parentViewController: navigationController)
notificationsCoordinator.parentCoordinator = self notificationsCoordinator.parentCoordinator = self
childCoordinators.append(notificationsCoordinator)
notificationsCoordinator.start() notificationsCoordinator.start()
} }
...@@ -59,6 +61,7 @@ class TodayCoordinator: Coordinator { ...@@ -59,6 +61,7 @@ class TodayCoordinator: Coordinator {
} }
let onboardingCoordinator = OnboardingCoordinator(parentViewController: todayViewController, locationManager: LocationManager.shared) // get rid of singleton let onboardingCoordinator = OnboardingCoordinator(parentViewController: todayViewController, locationManager: LocationManager.shared) // get rid of singleton
onboardingCoordinator.parentCoordinator = self onboardingCoordinator.parentCoordinator = self
childCoordinators.append(onboardingCoordinator)
onboardingCoordinator.start() onboardingCoordinator.start()
} }
...@@ -66,6 +69,20 @@ class TodayCoordinator: Coordinator { ...@@ -66,6 +69,20 @@ class TodayCoordinator: Coordinator {
parentCoordinator?.childDidFinish(child: self) parentCoordinator?.childDidFinish(child: self)
} }
@available(iOS 14, *)
func openWidgetPromotionIfNeeded() {
guard Settings.shared.widgetPromotionTriggerCount == 0 else {
return
}
guard let todayController = todayViewController else { return }
let promotionCoordinator = WidgetPromotionCoordinator(parentViewController: todayController)
promotionCoordinator.parentCoordinator = self
childCoordinators.append(promotionCoordinator)
promotionCoordinator.start()
}
func childDidFinish(child: Coordinator) { func childDidFinish(child: Coordinator) {
self.delegate?.childCoordinatorDidFinish(in: self) self.delegate?.childCoordinatorDidFinish(in: self)
......
//
// WidgetPromotionCoordinator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import UIKit
import OneWeatherCore
@available(iOS 14, *)
class WidgetPromotionCoordinator: Coordinator {
//Private
private let parentViewController: UIViewController
//Public
var childCoordinators = [Coordinator]()
var parentCoordinator: Coordinator?
init(parentViewController: UIViewController) {
self.parentViewController = parentViewController
}
func start() {
let controller = WidgetPromotionController(coordinator: self)
parentViewController.present(controller, animated: true)
Settings.shared.widgetPromotionTriggerCount = -1
}
func viewControllerDidEnd(controller: UIViewController) {
self.parentCoordinator?.childDidFinish(child: self)
}
}
//
// UIApplication+Version.swift
// 1Weather
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import UIKit
extension UIApplication {
struct AppVersion {
static var versionString: String? {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
}
static var buildNumber: String? {
Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String
}
static var major: Int {
guard let appVersion = self.versionString else {
return 0
}
guard let majorString = appVersion.components(separatedBy: ".").first else {
return 0
}
return Int(majorString) ?? 0
}
static var minor: Int {
guard let appVersion = self.versionString else {
return 0
}
let components = appVersion.components(separatedBy: ".")
guard components.count >= 2 else { return 0 }
return Int(components[1]) ?? 0
}
static var patch: Int {
guard let appVersion = self.versionString else {
return 0
}
guard let patchString = appVersion.components(separatedBy: ".").last else {
return 0
}
return Int(patchString) ?? 0
}
}
}
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>GADApplicationIdentifier</key> <key>GADApplicationIdentifier</key>
<string>ca-app-pub-7118865896152167~5937109115</string> <string>ca-app-pub-7118865896152167~5937109115</string>
<key>GADNativeAdValidatorEnabled</key>
<false/>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
...@@ -43,6 +45,8 @@ ...@@ -43,6 +45,8 @@
</dict> </dict>
<key>NSLocationWhenInUseUsageDescription</key> <key>NSLocationWhenInUseUsageDescription</key>
<string>Enabling location services helps us to provide you more accurate weather forecasts, weather alerts &amp; ads even when the app is closed or not in use. Heres our Privacy Policy: 1weatherapp.com/privacy</string> <string>Enabling location services helps us to provide you more accurate weather forecasts, weather alerts &amp; ads even when the app is closed or not in use. Heres our Privacy Policy: 1weatherapp.com/privacy</string>
<key>NSUserTrackingUsageDescription</key>
<string>This will be used to deliver personalized ads to you.</string>
<key>SKAdNetworkItems</key> <key>SKAdNetworkItems</key>
<array> <array>
<dict> <dict>
...@@ -422,9 +426,5 @@ ...@@ -422,9 +426,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>GADNativeAdValidatorEnabled</key>
<false/>
<key>NSUserTrackingUsageDescription</key>
<string>This will be used to deliver personalized ads to you.</string>
</dict> </dict>
</plist> </plist>
...@@ -283,3 +283,7 @@ ...@@ -283,3 +283,7 @@
"widget.promotion.medium" = "Medium"; "widget.promotion.medium" = "Medium";
"widget.promotion.large" = "Large"; "widget.promotion.large" = "Large";
"widget.promotion.learn" = "Learn to add widget"; "widget.promotion.learn" = "Learn to add widget";
//Widget
"widget.small.title" = "Temperature Forecast";
"widget.small.description" = "";
...@@ -47,6 +47,14 @@ class TodayViewController: UIViewController { ...@@ -47,6 +47,14 @@ class TodayViewController: UIViewController {
viewModel.updateWeather() viewModel.updateWeather()
} }
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if #available(iOS 14, *) {
coordinator.openWidgetPromotionIfNeeded()
}
}
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
viewModel.showOnboardingOrPrivacyNoticeIfNeeded() viewModel.showOnboardingOrPrivacyNoticeIfNeeded()
...@@ -65,11 +73,7 @@ class TodayViewController: UIViewController { ...@@ -65,11 +73,7 @@ class TodayViewController: UIViewController {
} }
@objc private func handleNotificationButton() { @objc private func handleNotificationButton() {
if #available(iOS 14, *) { self.coordinator.openNotificationsScreen()
self.present(WidgetPromotionController(), animated: true)
}
// self.coordinator.openNotificationsScreen()
} }
} }
......
...@@ -6,9 +6,12 @@ ...@@ -6,9 +6,12 @@
// //
import UIKit import UIKit
import SwiftUI
import OneWeatherUI
@available(iOS 14, *)
class PromotionSmallWidgetView: UIView { class PromotionSmallWidgetView: UIView {
private let widgetPlaceholder = UIView() private let widgetViewController = UIHostingController(rootView: SmallTemperatureWidgetView(widgetViewModel: nil))
private let topLabel = UILabel() private let topLabel = UILabel()
private let horizontalLineView = UIView() private let horizontalLineView = UIView()
private let verticalLineView = UIView() private let verticalLineView = UIView()
...@@ -18,7 +21,7 @@ class PromotionSmallWidgetView: UIView { ...@@ -18,7 +21,7 @@ class PromotionSmallWidgetView: UIView {
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
preparePlaceholder() prepareWidget()
prepareTopLabel() prepareTopLabel()
prepareHorizontalLine() prepareHorizontalLine()
prepareSizesLabel() prepareSizesLabel()
...@@ -53,12 +56,13 @@ class PromotionSmallWidgetView: UIView { ...@@ -53,12 +56,13 @@ class PromotionSmallWidgetView: UIView {
} }
//MARK:- Prepare //MARK:- Prepare
@available(iOS 14, *)
private extension PromotionSmallWidgetView { private extension PromotionSmallWidgetView {
func preparePlaceholder() { func prepareWidget() {
widgetPlaceholder.backgroundColor = .lightGray widgetViewController.view.layer.cornerRadius = 12
addSubview(widgetPlaceholder) addSubview(widgetViewController.view)
widgetPlaceholder.snp.makeConstraints { make in widgetViewController.view.snp.makeConstraints { make in
make.width.height.equalTo(158) make.width.height.equalTo(158)
make.left.equalToSuperview().inset(18) make.left.equalToSuperview().inset(18)
make.top.equalToSuperview().inset(16) make.top.equalToSuperview().inset(16)
...@@ -84,8 +88,8 @@ private extension PromotionSmallWidgetView { ...@@ -84,8 +88,8 @@ private extension PromotionSmallWidgetView {
addSubview(topLabel) addSubview(topLabel)
topLabel.snp.makeConstraints { make in topLabel.snp.makeConstraints { make in
make.left.equalTo(widgetPlaceholder.snp.right).offset(14) make.left.equalTo(widgetViewController.view.snp.right).offset(14)
make.top.equalTo(widgetPlaceholder) make.top.equalTo(widgetViewController.view)
} }
} }
......
...@@ -12,6 +12,7 @@ class WidgetPromotionController: UIViewController { ...@@ -12,6 +12,7 @@ class WidgetPromotionController: UIViewController {
//Private //Private
private let kPanTopInset: CGFloat = 10 private let kPanTopInset: CGFloat = 10
private let kScrollViewTopInset: CGFloat = 36 private let kScrollViewTopInset: CGFloat = 36
private let coordinator: WidgetPromotionCoordinator
private let controllerPanView = UIView() private let controllerPanView = UIView()
private let closeButton = UIButton() private let closeButton = UIButton()
private let scrollView = UIScrollView() private let scrollView = UIScrollView()
...@@ -35,7 +36,8 @@ class WidgetPromotionController: UIViewController { ...@@ -35,7 +36,8 @@ class WidgetPromotionController: UIViewController {
return pan + kScrollViewTopInset + stackHeight + scrollViewBottomInset + footerHeight + safeAreaInset return pan + kScrollViewTopInset + stackHeight + scrollViewBottomInset + footerHeight + safeAreaInset
} }
init() { init(coordinator: WidgetPromotionCoordinator) {
self.coordinator = coordinator
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom modalPresentationStyle = .custom
...@@ -58,12 +60,23 @@ class WidgetPromotionController: UIViewController { ...@@ -58,12 +60,23 @@ class WidgetPromotionController: UIViewController {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
private func close() {
self.dismiss(animated: true) {
self.coordinator.viewControllerDidEnd(controller: self)
}
}
@objc private func handleCloseButton() { @objc private func handleCloseButton() {
self.dismiss(animated: true) close()
} }
@objc private func handleLearnButton() { @objc private func handleLearnButton() {
guard let learnURL = URL(string: "https://support.apple.com/HT207122") else { return }
if UIApplication.shared.canOpenURL(learnURL) {
UIApplication.shared.open(learnURL, options: [:])
close()
}
} }
@objc private func handlePanGesture(sender: UIPanGestureRecognizer) { @objc private func handlePanGesture(sender: UIPanGestureRecognizer) {
...@@ -79,7 +92,7 @@ class WidgetPromotionController: UIViewController { ...@@ -79,7 +92,7 @@ class WidgetPromotionController: UIViewController {
} }
case .cancelled, .ended: case .cancelled, .ended:
if touchPoint.y - initialTouchPoint.y > 80 { if touchPoint.y - initialTouchPoint.y > 80 {
self.dismiss(animated: true, completion: nil) close()
} else { } else {
UIView.animate(withDuration: 0.25, animations: { UIView.animate(withDuration: 0.25, animations: {
self.view.frame.origin.y = originalOffsetY self.view.frame.origin.y = originalOffsetY
......
...@@ -78,10 +78,10 @@ public class Settings { ...@@ -78,10 +78,10 @@ public class Settings {
} }
@UserDefaultsBasicValue(key: "pinnedLayers") @UserDefaultsBasicValue(key: "pinnedLayers")
public var pinnedLayerIds:[String] = DefaultSettingsFactory().getSettings().pinnedLayerIds public var pinnedLayerIds: [String] = DefaultSettingsFactory().getSettings().pinnedLayerIds
@UserDefaultsBasicValue(key: "selectedLayer") @UserDefaultsBasicValue(key: "selectedLayer")
public var selectedLayerId:String = DefaultSettingsFactory().getSettings().selectedLayerId public var selectedLayerId: String = DefaultSettingsFactory().getSettings().selectedLayerId
@UserDefaultsOptionalValue("userQualifiedDate") @UserDefaultsOptionalValue("userQualifiedDate")
public var userQualifiedDate: Date? public var userQualifiedDate: Date?
...@@ -93,7 +93,10 @@ public class Settings { ...@@ -93,7 +93,10 @@ public class Settings {
public var d3RetentionDate: Date? public var d3RetentionDate: Date?
@UserDefaultsBasicValue(key: "locationDidAdded") @UserDefaultsBasicValue(key: "locationDidAdded")
public var locationDidAdded:Bool = false public var locationDidAdded: Bool = false
@UserDefaultsOptionalValue("widgetPromotionTriggerCount")
public var widgetPromotionTriggerCount: Int?
#warning("Not implemented!") #warning("Not implemented!")
//TODO: implement store in UserDefaults and configure via UI in debug builds. //TODO: implement store in UserDefaults and configure via UI in debug builds.
......
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x34",
"green" : "0x23",
"red" : "0x21"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF0",
"green" : "0x71",
"red" : "0x10"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF0",
"green" : "0x71",
"red" : "0x10"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{ {
"colors" : [ "images" : [
{ {
"filename" : "location_arrow.pdf",
"idiom" : "universal" "idiom" : "universal"
} }
], ],
"info" : { "info" : {
"author" : "xcode", "author" : "xcode",
"version" : 1 "version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
} }
} }
{ {
"colors" : [ "images" : [
{ {
"filename" : "partlyCloudyDay.pdf",
"idiom" : "universal" "idiom" : "universal"
} }
], ],
"info" : { "info" : {
"author" : "xcode", "author" : "xcode",
"version" : 1 "version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
} }
} }
//
// OneWeatherUI+Global.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import Foundation
struct OneWeatherUI {}
extension OneWeatherUI {
private class OneWeatherUIClass {}
static let frameworkBundle = Bundle(for: OneWeatherUIClass.self)
}
// //
// UIColor+Color.swift // UIColor+Color.swift
// OneWeatherWidgetExtension // OneWeatherUI
// //
// Created by Dmitry Stepanets on 04.06.2021. // Created by Dmitry Stepanets on 04.06.2021.
// //
...@@ -8,8 +8,9 @@ ...@@ -8,8 +8,9 @@
import SwiftUI import SwiftUI
import UIKit import UIKit
@available(iOS 14, *)
extension UIColor { extension UIColor {
var color:Color { var color: Color {
return Color(self) return Color(self)
} }
} }
//
// UIFont+Font.swift
// OneWeatherWidgetExtension
//
// Created by Dmitry Stepanets on 04.06.2021.
//
import SwiftUI
import UIKit
@available(iOS 14, *)
public extension UIFont {
var font: Font {
return Font(self)
}
internal static func loadFontWith(name: String, fileExtension: String) {
guard let pathForResource = OneWeatherUI.frameworkBundle.path(forResource: name, ofType: fileExtension) else {
print("[OneWeatherUI] Failed to load font \(name).\(fileExtension)")
return
}
guard let fontData = NSData(contentsOfFile: pathForResource) else {
print("[OneWeatherUI] Invalid font data")
return
}
guard let dataProvider = CGDataProvider(data: fontData) else {
print("[OneWeatherUI] Invalid font data")
return
}
guard let fontRef = CGFont(dataProvider) else {
print("[OneWeatherUI] Invalid CGFont reference")
return
}
var errorRef: Unmanaged<CFError>? = nil
if CTFontManagerRegisterGraphicsFont(fontRef, &errorRef) == false {
print("[OneWeatherUI] Failed to register font, this font may have already been registered in the main bundle.")
}
}
static let loadOneWeatherUI: () = {
loadFontWith(name: "SF-Pro-Display-Regular", fileExtension: "otf")
loadFontWith(name: "SF-Pro-Display-Light", fileExtension: "otf")
}()
}
//
// UIImage+Resize.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import UIKit
extension UIImage {
func scalePreservingAspectRatio(targetSize: CGSize) -> UIImage {
// Determine the scale factor that preserves aspect ratio
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
let scaleFactor = min(widthRatio, heightRatio)
// Compute the new image size that preserves aspect ratio
let scaledImageSize = CGSize(
width: size.width * scaleFactor,
height: size.height * scaleFactor
)
// Draw and return the resized UIImage
let renderer = UIGraphicsImageRenderer(
size: scaledImageSize
)
let scaledImage = renderer.image { _ in
self.draw(in: CGRect(
origin: .zero,
size: scaledImageSize
))
}
return scaledImage
}
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
@available(iOS 14, *)
struct CityNameView: View { struct CityNameView: View {
@State public var cityName: String @State public var cityName: String
@State public var isDeviceLocation: Bool @State public var isDeviceLocation: Bool
...@@ -15,15 +16,24 @@ struct CityNameView: View { ...@@ -15,15 +16,24 @@ struct CityNameView: View {
HStack(spacing: 4) { HStack(spacing: 4) {
Text(cityName) Text(cityName)
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
.font(AppFont.SFProDisplay.regular(size: 12).font) .font(WidgetFont.SFProDisplay.regular(size: 12).font)
.foregroundColor(ThemeManager.currentTheme.graphTintColor.color) .foregroundColor(Color("PrimaryTintColor", bundle: OneWeatherUI.frameworkBundle))
Image("location_arrow") arrowImage()
.resizable()
.renderingMode(.template) .renderingMode(.template)
.frame(width: 8, height: 8, alignment: .center) .frame(width: 8, height: 8, alignment: .center)
.aspectRatio(contentMode: .fit) .foregroundColor(Color("PrimaryTintColor", bundle: OneWeatherUI.frameworkBundle))
.foregroundColor(Color(ThemeManager.currentTheme.graphTintColor.cgColor))
.opacity(isDeviceLocation ? 1 : 0) .opacity(isDeviceLocation ? 1 : 0)
} }
} }
} }
@available(iOS 14, *)
private extension CityNameView {
func arrowImage() -> Image {
guard let arrow = UIImage(named: "location_arrow", in: OneWeatherUI.frameworkBundle, compatibleWith: nil) else {
return Image("")
}
return Image(uiImage: arrow.scalePreservingAspectRatio(targetSize: .init(width: 8, height: 8)))
}
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
@available(iOS 14, *)
struct HighLowTemperatureView: View { struct HighLowTemperatureView: View {
@State public var highTemperature: String @State public var highTemperature: String
@State public var lowTemperature: String @State public var lowTemperature: String
...@@ -14,11 +15,11 @@ struct HighLowTemperatureView: View { ...@@ -14,11 +15,11 @@ struct HighLowTemperatureView: View {
var body: some View { var body: some View {
HStack { HStack {
Text("H \(highTemperature)") Text("H \(highTemperature)")
.font(AppFont.SFProDisplay.regular(size: 12).font) .font(WidgetFont.SFProDisplay.regular(size: 12).font)
.foregroundColor(Color("HighLowTemperatureColor")) .foregroundColor(Color("HighLowTemperatureColor", bundle: OneWeatherUI.frameworkBundle))
Text("L \(lowTemperature)") Text("L \(lowTemperature)")
.font(AppFont.SFProDisplay.regular(size: 12).font) .font(WidgetFont.SFProDisplay.regular(size: 12).font)
.foregroundColor(Color("HighLowTemperatureColor")) .foregroundColor(Color("HighLowTemperatureColor", bundle: OneWeatherUI.frameworkBundle))
} }
} }
} }
...@@ -7,25 +7,20 @@ ...@@ -7,25 +7,20 @@
import SwiftUI import SwiftUI
import WidgetKit import WidgetKit
import OneWeatherCore
struct SmallTemperatureWidgetView: View { @available(iOS 14, *)
public struct SmallTemperatureWidgetView: View {
//Public //Public
let widgetViewModel: ForecastWidgetViewModel public let widgetViewModel: WidgetViewModel
public init(widgetViewModel: WidgetViewModel?) {
self.widgetViewModel = widgetViewModel ?? WidgetViewModelMock()
}
//Private //Private
@Environment(\.colorScheme) private var colorScheme @Environment(\.colorScheme) private var colorScheme
private var interfaceStyle: AppInterfaceStyle { public var body: some View {
if #available(iOS 13, *) {
return colorScheme == .light ? .light : .dark
}
else {
return .light
}
}
var body: some View {
GeometryReader { geometry in GeometryReader { geometry in
VStack { VStack {
HStack(spacing: 4) { HStack(spacing: 4) {
...@@ -39,23 +34,23 @@ struct SmallTemperatureWidgetView: View { ...@@ -39,23 +34,23 @@ struct SmallTemperatureWidgetView: View {
HStack(spacing: 0) { HStack(spacing: 0) {
VStack(alignment: .leading){ VStack(alignment: .leading){
Text(widgetViewModel.temperature) Text(widgetViewModel.temperature)
.font(AppFont.SFProDisplay.light(size: 32).font) .font(WidgetFont.SFProDisplay.light(size: 32).font)
.padding(.leading, 10) .padding(.leading, 10)
.padding(.trailing, 4) .padding(.trailing, 4)
.textColor(for: colorScheme) .foregroundColor(Color("PrimaryTextColor",
bundle: OneWeatherUI.frameworkBundle))
Text(widgetViewModel.weatherType) Text(widgetViewModel.weatherType)
.font(AppFont.SFProDisplay.regular(size: 12).font) .font(WidgetFont.SFProDisplay.regular(size: 12).font)
.padding(.leading, 10) .padding(.leading, 10)
.padding(.trailing, 4) .padding(.trailing, 4)
.textColor(for: colorScheme) .foregroundColor(Color("PrimaryTextColor",
bundle: OneWeatherUI.frameworkBundle))
Spacer(minLength: 0) Spacer(minLength: 0)
} }
.frame(height: 70) .frame(height: 70)
Spacer(minLength: 0) Spacer(minLength: 0)
Image(uiImage: widgetViewModel.weatherIcon) weatherImage(uiImage: widgetViewModel.weatherIcon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 70, height: 70, alignment: .center) .frame(width: 70, height: 70, alignment: .center)
.shadow(for: colorScheme) .shadow(for: colorScheme)
.padding(.trailing, 4) .padding(.trailing, 4)
...@@ -74,6 +69,7 @@ struct SmallTemperatureWidgetView: View { ...@@ -74,6 +69,7 @@ struct SmallTemperatureWidgetView: View {
} }
//MARK: Appearence extension //MARK: Appearence extension
@available(iOS 14, *)
private extension View { private extension View {
func shadow(for colorScheme: ColorScheme) -> some View { func shadow(for colorScheme: ColorScheme) -> some View {
switch colorScheme { switch colorScheme {
...@@ -86,22 +82,15 @@ private extension View { ...@@ -86,22 +82,15 @@ private extension View {
} }
} }
func textColor(for colorScheme: ColorScheme) -> some View { func weatherImage(uiImage: UIImage) -> Image {
switch colorScheme { return Image(uiImage: uiImage.scalePreservingAspectRatio(targetSize: .init(width: 70, height: 70)))
case .light:
return self.foregroundColor(ThemeManager.currentTheme.secondaryTextColor.color)
case .dark:
return self.foregroundColor(ThemeManager.currentTheme.primaryTextColor.color)
@unknown default:
return self.foregroundColor(ThemeManager.currentTheme.secondaryTextColor.color)
}
} }
} }
@available(iOS 14, *)
struct SmallTemperatureWidgetView_Preview: PreviewProvider { public struct SmallTemperatureWidgetView_Preview: PreviewProvider {
static var previews: some View { public static var previews: some View {
SmallTemperatureWidgetView(widgetViewModel: .init(location: WeatherEntry.defaultLocation)) SmallTemperatureWidgetView(widgetViewModel: WidgetViewModelMock())
.previewContext(WidgetPreviewContext(family: .systemSmall)) .frame(width: 158, height: 158)
} }
} }
//
// WidgetFont.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import UIKit
@available(iOS 14, *)
struct WidgetFont {
private static var fontsLoaded = false
init() {
if !WidgetFont.fontsLoaded {
UIFont.loadOneWeatherUI
WidgetFont.fontsLoaded = true
}
}
private static func fontDescriptor(family: String, size:CGFloat, weight:UIFont.Weight) -> UIFontDescriptor {
let traitsDict = [UIFontDescriptor.TraitKey.weight: weight]
let descriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptor.AttributeName.size : size,
UIFontDescriptor.AttributeName.family : family,
UIFontDescriptor.AttributeName.traits : traitsDict
])
return descriptor
}
struct SFProDisplay {
private static var fontCache = [UIFont.Weight: [CGFloat: UIFont]]()
static func font(weigth: UIFont.Weight, size: CGFloat) -> UIFont {
if let cached = fontCache[weigth]?[size] {
return cached
}
let descriptor = WidgetFont.fontDescriptor(family: "SF Pro Display", size: size, weight: weigth)
let font = UIFont(descriptor: descriptor, size: size)
if fontCache[weigth] == nil {
fontCache[weigth] = [size: font]
}
else {
fontCache[weigth]![size] = font
}
return font
}
static func light(size: CGFloat) -> UIFont {
font(weigth: .light, size: size)
}
static func regular(size: CGFloat) -> UIFont {
font(weigth: .regular, size: size)
}
}
}
//
// WidgetViewModel.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import UIKit
@available(iOS 14, *)
public protocol WidgetViewModel {
var cityName: String { get }
var temperature: String { get }
var weatherType: String { get }
var weatherIcon: UIImage { get }
var highTemperature: String { get }
var lowTemperature: String { get }
var isDeviceLocation: Bool { get }
}
//
// WidgetViewModelMock.swift
// OneWeatherUI
//
// Created by Dmitry Stepanets on 02.07.2021.
//
import UIKit
@available(iOS 14, *)
struct WidgetViewModelMock: WidgetViewModel {
private class OneWeatherUIClass {}
let cityName = "New York"
let temperature = "96°"
let weatherType = "Partly Cloudy"
let weatherIcon = UIImage(named: "partlyCloudyDay", in: Bundle(for: OneWeatherUIClass.self), compatibleWith: nil)!
let highTemperature = "97°"
let lowTemperature = "89°"
let isDeviceLocation = true
}
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
//
// UIFont+Font.swift
// OneWeatherWidgetExtension
//
// Created by Dmitry Stepanets on 04.06.2021.
//
import SwiftUI
import UIKit
extension UIFont {
var font:Font {
return Font(self)
}
}
//
// VectorImage.swift
// OneWeatherWidgetExtension
//
// Created by Dmitry Stepanets on 07.06.2021.
//
import SwiftUI
import WidgetKit
struct VectorImage: UIViewRepresentable {
typealias UIViewType = UIImageView
var name: String
var contentMode: UIView.ContentMode = .scaleAspectFit
var tintColor:UIColor = .black
private var image: UIImage?
init(image:UIImage, contentMode: UIView.ContentMode = .scaleAspectFit, tintColor:UIColor = .black) {
self.image = image
self.contentMode = contentMode
self.tintColor = tintColor
self.name = ""
}
init(name:String, contentMode: UIView.ContentMode = .scaleAspectFit, tintColor:UIColor = .black) {
self.name = name
self.contentMode = contentMode
self.tintColor = tintColor
}
func makeUIView(context: Context) -> UIViewType {
let imageView = UIImageView()
imageView.setContentCompressionResistancePriority(.fittingSizeLevel,
for: .vertical)
imageView.image = image
imageView.contentMode = contentMode
imageView.tintColor = tintColor
return imageView
}
func updateUIView(_ uiView: UIViewType, context: Context) {
uiView.contentMode = contentMode
uiView.tintColor = tintColor
if self.image != nil {
uiView.image = self.image
}
else {
uiView.image = UIImage(named: name)
}
}
}
struct VectorImage_Preview: PreviewProvider {
static var previews: some View {
VectorImage(image: UIImage())
.previewLayout(.fixed(width: 200, height: 200))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
import WidgetKit import WidgetKit
import OneWeatherUI
struct WidgetPlaceholderView: View { struct WidgetPlaceholderView: View {
@Environment(\.widgetFamily) var family @Environment(\.widgetFamily) var family
...@@ -14,10 +15,10 @@ struct WidgetPlaceholderView: View { ...@@ -14,10 +15,10 @@ struct WidgetPlaceholderView: View {
var body: some View { var body: some View {
switch family { switch family {
case .systemSmall: case .systemSmall:
SmallTemperatureWidgetView(widgetViewModel: .init(location: WeatherEntry.defaultLocation)) SmallTemperatureWidgetView(widgetViewModel: ForecastWidgetViewModel(location: WeatherEntry.defaultLocation))
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
default: default:
SmallTemperatureWidgetView(widgetViewModel: .init(location: WeatherEntry.defaultLocation)) SmallTemperatureWidgetView(widgetViewModel: ForecastWidgetViewModel(location: WeatherEntry.defaultLocation))
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
} }
} }
......
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
import SwiftUI import SwiftUI
import OneWeatherCore import OneWeatherCore
import OneWeatherUI
struct ForecastWidgetViewModel { struct ForecastWidgetViewModel: WidgetViewModel {
let cityName: String let cityName: String
let temperature: String let temperature: String
let weatherType: String let weatherType: String
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
import WidgetKit import WidgetKit
import SwiftUI import SwiftUI
import OneWeatherUI
import Localize_Swift
struct SmallTemperatureWidget: Widget { struct SmallTemperatureWidget: Widget {
private let kind = "com.onelouder.oneweather.widget.small" private let kind = "com.onelouder.oneweather.widget.small"
...@@ -14,8 +16,18 @@ struct SmallTemperatureWidget: Widget { ...@@ -14,8 +16,18 @@ struct SmallTemperatureWidget: Widget {
var body: some WidgetConfiguration { 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. // 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 StaticConfiguration(kind: kind, provider: WeatherProvider()) { weatherEntry in
SmallTemperatureWidgetView(widgetViewModel: .init(location: weatherEntry.location)) SmallTemperatureWidgetView(widgetViewModel: ForecastWidgetViewModel(location: weatherEntry.location))
} }
.configurationDisplayName("widget.small.title".localized())
.description("widget.small.description".localized())
.supportedFamilies([.systemSmall]) .supportedFamilies([.systemSmall])
} }
} }
struct SmallTemperatureWidgetView_Preview: PreviewProvider {
public static var previews: some View {
SmallTemperatureWidgetView(widgetViewModel: nil)
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
...@@ -71,6 +71,11 @@ target 'OneWeatherCore' do ...@@ -71,6 +71,11 @@ target 'OneWeatherCore' do
core_pods core_pods
end end
#UI
target 'OneWeatherUI' do
project 'OneWeatherUI/OneWeatherUI.project'
end
#CoreDataStorage #CoreDataStorage
target 'CoreDataStorage' do target 'CoreDataStorage' do
project 'CoreDataStorage/CoreDataStorage.project' project 'CoreDataStorage/CoreDataStorage.project'
...@@ -105,6 +110,10 @@ target 'OneWeatherNotificationServiceExtension' do ...@@ -105,6 +110,10 @@ target 'OneWeatherNotificationServiceExtension' do
pod 'MORichNotification' pod 'MORichNotification'
end end
target 'OneWeatherWidgetExtension' do
pod 'Localize-Swift'
end
#post_install do |installer| #post_install do |installer|
# applicationTargets = [ # applicationTargets = [
# 'Pods-1Weather' # 'Pods-1Weather'
......
...@@ -290,6 +290,6 @@ SPEC CHECKSUMS: ...@@ -290,6 +290,6 @@ SPEC CHECKSUMS:
Swarm: 95393cd52715744c94e3a8475bc20b4de5d79f35 Swarm: 95393cd52715744c94e3a8475bc20b4de5d79f35
XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028 XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028
PODFILE CHECKSUM: bbdc2e45e39585408b836ebe285837b990c3bb9f PODFILE CHECKSUM: 659661f4f40b1e968a316ebeaf2afc8bc6f0190a
COCOAPODS: 1.10.1 COCOAPODS: 1.10.1
...@@ -290,6 +290,6 @@ SPEC CHECKSUMS: ...@@ -290,6 +290,6 @@ SPEC CHECKSUMS:
Swarm: 95393cd52715744c94e3a8475bc20b4de5d79f35 Swarm: 95393cd52715744c94e3a8475bc20b4de5d79f35
XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028 XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028
PODFILE CHECKSUM: bbdc2e45e39585408b836ebe285837b990c3bb9f PODFILE CHECKSUM: 659661f4f40b1e968a316ebeaf2afc8bc6f0190a
COCOAPODS: 1.10.1 COCOAPODS: 1.10.1
This source diff could not be displayed because it is too large. You can view the blob instead.
APPLICATION_EXTENSION_API_ONLY = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
......
APPLICATION_EXTENSION_API_ONLY = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
# Acknowledgements
This application makes use of the following third party libraries:
Generated by CocoaPods - https://cocoapods.org
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_OneWeatherUI : NSObject
@end
@implementation PodsDummy_Pods_OneWeatherUI
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double Pods_OneWeatherUIVersionNumber;
FOUNDATION_EXPORT const unsigned char Pods_OneWeatherUIVersionString[];
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/..
PODS_ROOT = ${SRCROOT}/../Pods
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module Pods_OneWeatherUI {
umbrella header "Pods-OneWeatherUI-umbrella.h"
export *
module * { export * }
}
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/..
PODS_ROOT = ${SRCROOT}/../Pods
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
# Acknowledgements
This application makes use of the following third party libraries:
## Localize-Swift
Copyright (c) 2015 Roy Marmelstein (http://roysapps.com/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Generated by CocoaPods - https://cocoapods.org
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>FooterText</key>
<string>This application makes use of the following third party libraries:</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2015 Roy Marmelstein (http://roysapps.com/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>Localize-Swift</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>Title</key>
<string>Acknowledgements</string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_Pods_OneWeatherWidgetExtension : NSObject
@end
@implementation PodsDummy_Pods_OneWeatherWidgetExtension
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double Pods_OneWeatherWidgetExtensionVersionNumber;
FOUNDATION_EXPORT const unsigned char Pods_OneWeatherWidgetExtensionVersionString[];
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift/Localize_Swift.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "Localize_Swift"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module Pods_OneWeatherWidgetExtension {
umbrella header "Pods-OneWeatherWidgetExtension-umbrella.h"
export *
module * { export * }
}
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift/Localize_Swift.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "Localize_Swift"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
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