Commit b2cede04 by Demid Merzlyakov

Merge branch 'feature/IOS-73-native-ads' into develop

# Conflicts:
#	1Weather.xcodeproj/project.pbxproj
#	1Weather/Ads/Configuration/AdConfig.swift
#	1Weather/Ads/Configuration/AdConfigManager.swift
parents 2719e434 fda52da8
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
87B66BEC2667A45800B9A59A /* SF-Compact-Display-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 87B66BEA2667A44F00B9A59A /* SF-Compact-Display-Semibold.otf */; };
87B66BED2667A45B00B9A59A /* SF-Compact-Display-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 87B66BEB2667A44F00B9A59A /* SF-Compact-Display-Regular.otf */; };
87B66BF12667AF1C00B9A59A /* SF-Compact-Display-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 87B66BF02667AF1900B9A59A /* SF-Compact-Display-Light.otf */; };
87C171ED25FF79CC00DA3464 /* LocalConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = 87C171E925FF79CC00DA3464 /* LocalConfig.plist */; }; 87C171ED25FF79CC00DA3464 /* LocalConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = 87C171E925FF79CC00DA3464 /* LocalConfig.plist */; };
87C171F425FF7A4000DA3464 /* PopularCitiesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C171F325FF7A4000DA3464 /* PopularCitiesManager.swift */; }; 87C171F425FF7A4000DA3464 /* PopularCitiesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C171F325FF7A4000DA3464 /* PopularCitiesManager.swift */; };
87D815AA2636D5E60015A6D1 /* NWSAlertCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D815A92636D5E60015A6D1 /* NWSAlertCoordinator.swift */; }; 87D815AA2636D5E60015A6D1 /* NWSAlertCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D815A92636D5E60015A6D1 /* NWSAlertCoordinator.swift */; };
87D815AC2636D61D0015A6D1 /* NWSAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D815AB2636D61D0015A6D1 /* NWSAlertViewModel.swift */; }; 87D815AC2636D61D0015A6D1 /* NWSAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D815AB2636D61D0015A6D1 /* NWSAlertViewModel.swift */; };
C27F92C189A9C9E637AF6C3A /* Pods_OneWeatherNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 871EA87D239E6F89F6F8818E /* Pods_OneWeatherNotificationServiceExtension.framework */; };
CD1237C3255D5C5900C98139 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1237C2255D5C5900C98139 /* AppDelegate.swift */; }; CD1237C3255D5C5900C98139 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1237C2255D5C5900C98139 /* AppDelegate.swift */; };
CD1237CC255D5C5C00C98139 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD1237CB255D5C5C00C98139 /* Assets.xcassets */; }; CD1237CC255D5C5C00C98139 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD1237CB255D5C5C00C98139 /* Assets.xcassets */; };
CD1237F4255D889F00C98139 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1237F3255D889F00C98139 /* GradientView.swift */; }; CD1237F4255D889F00C98139 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1237F3255D889F00C98139 /* GradientView.swift */; };
...@@ -148,17 +150,15 @@ ...@@ -148,17 +150,15 @@
CDFE45BD26566EF50021A29F /* WDTWeatherSource.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CDFE45BB26566EF50021A29F /* WDTWeatherSource.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CDFE45BD26566EF50021A29F /* WDTWeatherSource.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CDFE45BB26566EF50021A29F /* WDTWeatherSource.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CE0457902632B3BC00B3C19A /* NotificationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE04578F2632B3BC00B3C19A /* NotificationsViewModel.swift */; }; CE0457902632B3BC00B3C19A /* NotificationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE04578F2632B3BC00B3C19A /* NotificationsViewModel.swift */; };
CE0457952632B3F900B3C19A /* NotificationsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0457942632B3F900B3C19A /* NotificationsCoordinator.swift */; }; CE0457952632B3F900B3C19A /* NotificationsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0457942632B3F900B3C19A /* NotificationsCoordinator.swift */; };
CE0DB57A267248580087E07A /* OneWeatherAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE0DB579267248580087E07A /* OneWeatherAnalytics.framework */; };
CE0DB57B267248580087E07A /* OneWeatherAnalytics.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE0DB579267248580087E07A /* OneWeatherAnalytics.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CE0DB57C26724C240087E07A /* Pods_OneWeatherNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 871EA87D239E6F89F6F8818E /* Pods_OneWeatherNotificationServiceExtension.framework */; };
CE0DB57D26724C240087E07A /* Pods_OneWeatherNotificationServiceExtension.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 871EA87D239E6F89F6F8818E /* Pods_OneWeatherNotificationServiceExtension.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CE13B76326246743007CBD4D /* CCPAHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B76226246743007CBD4D /* CCPAHelper.swift */; }; CE13B76326246743007CBD4D /* CCPAHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B76226246743007CBD4D /* CCPAHelper.swift */; };
CE13B80E262480B3007CBD4D /* StoriesNativeAd.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE13B7F3262480B3007CBD4D /* StoriesNativeAd.xib */; }; CE13B80F262480B3007CBD4D /* NativeBannerContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7F4262480B3007CBD4D /* NativeBannerContainerView.swift */; };
CE13B80F262480B3007CBD4D /* BRNativeBannerContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7F4262480B3007CBD4D /* BRNativeBannerContainerView.swift */; };
CE13B810262480B3007CBD4D /* StoriesNativeAdCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE13B7F5262480B3007CBD4D /* StoriesNativeAdCell.xib */; };
CE13B811262480B3007CBD4D /* StoriesNativeAdCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7F6262480B3007CBD4D /* StoriesNativeAdCell.swift */; };
CE13B812262480B3007CBD4D /* NativeAdItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7F7262480B3007CBD4D /* NativeAdItem.swift */; }; CE13B812262480B3007CBD4D /* NativeAdItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7F7262480B3007CBD4D /* NativeAdItem.swift */; };
CE13B813262480B3007CBD4D /* StoriesLeftNativeAd.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE13B7F8262480B3007CBD4D /* StoriesLeftNativeAd.xib */; };
CE13B814262480B3007CBD4D /* BRNativeBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7F9262480B3007CBD4D /* BRNativeBannerView.swift */; };
CE13B815262480B3007CBD4D /* StoriesNativeAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7FA262480B3007CBD4D /* StoriesNativeAd.swift */; };
CE13B816262480B3007CBD4D /* NativeAdLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7FB262480B3007CBD4D /* NativeAdLoader.swift */; }; CE13B816262480B3007CBD4D /* NativeAdLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7FB262480B3007CBD4D /* NativeAdLoader.swift */; };
CE13B817262480B3007CBD4D /* BRNativeBannerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE13B7FC262480B3007CBD4D /* BRNativeBannerView.xib */; }; CE13B817262480B3007CBD4D /* NativeBannerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE13B7FC262480B3007CBD4D /* NativeBannerView.xib */; };
CE13B818262480B3007CBD4D /* A9BidObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7FF262480B3007CBD4D /* A9BidObject.swift */; }; CE13B818262480B3007CBD4D /* A9BidObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B7FF262480B3007CBD4D /* A9BidObject.swift */; };
CE13B819262480B3007CBD4D /* A9Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B800262480B3007CBD4D /* A9Cache.swift */; }; CE13B819262480B3007CBD4D /* A9Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B800262480B3007CBD4D /* A9Cache.swift */; };
CE13B81A262480B3007CBD4D /* AdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B801262480B3007CBD4D /* AdManager.swift */; }; CE13B81A262480B3007CBD4D /* AdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE13B801262480B3007CBD4D /* AdManager.swift */; };
...@@ -178,15 +178,19 @@ ...@@ -178,15 +178,19 @@
CE578FE725FB415F00E8B85D /* LocationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE578FE425FB415F00E8B85D /* LocationsViewModel.swift */; }; CE578FE725FB415F00E8B85D /* LocationsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE578FE425FB415F00E8B85D /* LocationsViewModel.swift */; };
CE6BE4942634170800626822 /* USStateCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6BE4932634170800626822 /* USStateCode.swift */; }; CE6BE4942634170800626822 /* USStateCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6BE4932634170800626822 /* USStateCode.swift */; };
CE6F5F0C263C8B3D00973137 /* SmartTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6F5F0B263C8B3C00973137 /* SmartTextProvider.swift */; }; CE6F5F0C263C8B3D00973137 /* SmartTextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6F5F0B263C8B3C00973137 /* SmartTextProvider.swift */; };
CE81A422266E289E00800EFF /* NativeAdView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE81A421266E289E00800EFF /* NativeAdView.swift */; };
CE849DB82638C33600DEFFBD /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE849DB72638C33600DEFFBD /* NotificationService.swift */; }; CE849DB82638C33600DEFFBD /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE849DB72638C33600DEFFBD /* NotificationService.swift */; };
CE849DBC2638C33600DEFFBD /* OneWeatherNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CE849DB52638C33600DEFFBD /* OneWeatherNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; CE849DBC2638C33600DEFFBD /* OneWeatherNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CE849DB52638C33600DEFFBD /* OneWeatherNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
CE849E382638CE8000DEFFBD /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE849E372638CE8000DEFFBD /* UserNotifications.framework */; }; CE849E382638CE8000DEFFBD /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE849E372638CE8000DEFFBD /* UserNotifications.framework */; };
CE895F0F26393FD800214175 /* WeatherImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE895F0E26393FD800214175 /* WeatherImageProvider.swift */; }; CE895F0F26393FD800214175 /* WeatherImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE895F0E26393FD800214175 /* WeatherImageProvider.swift */; };
CE9C0780266A4768004197FC /* NativeMRECView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE9C077F266A4768004197FC /* NativeMRECView.xib */; };
CEBAC1C82638240800A89681 /* DeeplinksRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBAC1C72638240800A89681 /* DeeplinksRouter.swift */; }; CEBAC1C82638240800A89681 /* DeeplinksRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBAC1C72638240800A89681 /* DeeplinksRouter.swift */; };
CEC7D8EE2639FE2700B8836D /* OLInAppStoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC7D8ED2639FE2700B8836D /* OLInAppStoreManager.swift */; }; CEC7D8EE2639FE2700B8836D /* OLInAppStoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC7D8ED2639FE2700B8836D /* OLInAppStoreManager.swift */; };
CEC8FBAF2639756A0001A6BF /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC8FBAE2639756A0001A6BF /* OnboardingViewController.swift */; }; CEC8FBAF2639756A0001A6BF /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC8FBAE2639756A0001A6BF /* OnboardingViewController.swift */; };
CEC8FBB2263976240001A6BF /* OnboardingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC8FBB1263976240001A6BF /* OnboardingCoordinator.swift */; }; CEC8FBB2263976240001A6BF /* OnboardingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC8FBB1263976240001A6BF /* OnboardingCoordinator.swift */; };
CEC8FBB5263976400001A6BF /* OnboardingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC8FBB4263976400001A6BF /* OnboardingViewModel.swift */; }; CEC8FBB5263976400001A6BF /* OnboardingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC8FBB4263976400001A6BF /* OnboardingViewModel.swift */; };
CEEB3547266F5D9900E16F90 /* BannerAdCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEB3546266F5D9900E16F90 /* BannerAdCell.swift */; };
CEEB3549266F5DA900E16F90 /* MRECAdCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEB3548266F5DA900E16F90 /* MRECAdCell.swift */; };
CEEF4100265E47FF00425D8F /* BlendFIPSSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */; }; CEEF4100265E47FF00425D8F /* BlendFIPSSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */; };
CEEF4101265E47FF00425D8F /* BlendFIPSSource.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CEEF4101265E47FF00425D8F /* BlendFIPSSource.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
...@@ -202,6 +206,17 @@ ...@@ -202,6 +206,17 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
CE0DB57E26724C240087E07A /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
CE0DB57D26724C240087E07A /* Pods_OneWeatherNotificationServiceExtension.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
CE13B7922624748E007CBD4D /* Embed Frameworks */ = { CE13B7922624748E007CBD4D /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
...@@ -209,6 +224,7 @@ ...@@ -209,6 +224,7 @@
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
CDFE45BD26566EF50021A29F /* WDTWeatherSource.framework in Embed Frameworks */, CDFE45BD26566EF50021A29F /* WDTWeatherSource.framework in Embed Frameworks */,
CE0DB57B267248580087E07A /* OneWeatherAnalytics.framework in Embed Frameworks */,
CD4F6A2B266663C300252FE1 /* Pods_1Weather.framework in Embed Frameworks */, CD4F6A2B266663C300252FE1 /* Pods_1Weather.framework in Embed Frameworks */,
CEEF4101265E47FF00425D8F /* BlendFIPSSource.framework in Embed Frameworks */, CEEF4101265E47FF00425D8F /* BlendFIPSSource.framework in Embed Frameworks */,
CE13B97C2626FB11007CBD4D /* PSMLocationSDK.xcframework in Embed Frameworks */, CE13B97C2626FB11007CBD4D /* PSMLocationSDK.xcframework in Embed Frameworks */,
...@@ -237,14 +253,13 @@ ...@@ -237,14 +253,13 @@
6B543196B99BA697763514F6 /* Pods_1Weather.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_1Weather.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6B543196B99BA697763514F6 /* Pods_1Weather.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_1Weather.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7082B26061BEBA910124DD8A /* Pods-OneWeatherNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneWeatherNotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-OneWeatherNotificationServiceExtension/Pods-OneWeatherNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; }; 7082B26061BEBA910124DD8A /* Pods-OneWeatherNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneWeatherNotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-OneWeatherNotificationServiceExtension/Pods-OneWeatherNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
871EA87D239E6F89F6F8818E /* Pods_OneWeatherNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OneWeatherNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 871EA87D239E6F89F6F8818E /* Pods_OneWeatherNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OneWeatherNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
87B66BEA2667A44F00B9A59A /* SF-Compact-Display-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Compact-Display-Semibold.otf"; sourceTree = "<group>"; };
87B66BEB2667A44F00B9A59A /* SF-Compact-Display-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Compact-Display-Regular.otf"; sourceTree = "<group>"; };
87B66BF02667AF1900B9A59A /* SF-Compact-Display-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-Compact-Display-Light.otf"; sourceTree = "<group>"; };
87C171E925FF79CC00DA3464 /* LocalConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = LocalConfig.plist; sourceTree = "<group>"; }; 87C171E925FF79CC00DA3464 /* LocalConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = LocalConfig.plist; sourceTree = "<group>"; };
87C171F325FF7A4000DA3464 /* PopularCitiesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopularCitiesManager.swift; sourceTree = "<group>"; }; 87C171F325FF7A4000DA3464 /* PopularCitiesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopularCitiesManager.swift; sourceTree = "<group>"; };
87D815842636CFFD0015A6D1 /* NWSAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertViewController.swift; sourceTree = "<group>"; };
87D815A92636D5E60015A6D1 /* NWSAlertCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertCoordinator.swift; sourceTree = "<group>"; }; 87D815A92636D5E60015A6D1 /* NWSAlertCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertCoordinator.swift; sourceTree = "<group>"; };
87D815AB2636D61D0015A6D1 /* NWSAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertViewModel.swift; sourceTree = "<group>"; }; 87D815AB2636D61D0015A6D1 /* NWSAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertViewModel.swift; sourceTree = "<group>"; };
87D815AE2636E6BF0015A6D1 /* NWSForecastOfficeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSForecastOfficeTableViewCell.swift; sourceTree = "<group>"; };
87D815B02636ED850015A6D1 /* NWSAlertCellFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertCellFactory.swift; sourceTree = "<group>"; };
87D815B22636F2040015A6D1 /* NWSAlertInfoBlockTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertInfoBlockTableViewCell.swift; sourceTree = "<group>"; };
C8C576F6184B547435CFF0F3 /* Pods-1Weather.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-1Weather.debug.xcconfig"; path = "Target Support Files/Pods-1Weather/Pods-1Weather.debug.xcconfig"; sourceTree = "<group>"; }; C8C576F6184B547435CFF0F3 /* Pods-1Weather.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-1Weather.debug.xcconfig"; path = "Target Support Files/Pods-1Weather/Pods-1Weather.debug.xcconfig"; sourceTree = "<group>"; };
CD1237BF255D5C5900C98139 /* 1Weather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 1Weather.app; sourceTree = BUILT_PRODUCTS_DIR; }; CD1237BF255D5C5900C98139 /* 1Weather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 1Weather.app; sourceTree = BUILT_PRODUCTS_DIR; };
CD1237C2255D5C5900C98139 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; CD1237C2255D5C5900C98139 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
...@@ -378,21 +393,14 @@ ...@@ -378,21 +393,14 @@
CDF9BF8D26133D050037847D /* LocationSearchCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSearchCoordinator.swift; sourceTree = "<group>"; }; CDF9BF8D26133D050037847D /* LocationSearchCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSearchCoordinator.swift; sourceTree = "<group>"; };
CDFE45BB26566EF50021A29F /* WDTWeatherSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = WDTWeatherSource.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CDFE45BB26566EF50021A29F /* WDTWeatherSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = WDTWeatherSource.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CE04578F2632B3BC00B3C19A /* NotificationsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewModel.swift; sourceTree = "<group>"; }; CE04578F2632B3BC00B3C19A /* NotificationsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewModel.swift; sourceTree = "<group>"; };
CE0457922632B3DD00B3C19A /* NotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewController.swift; sourceTree = "<group>"; };
CE0457942632B3F900B3C19A /* NotificationsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsCoordinator.swift; sourceTree = "<group>"; }; CE0457942632B3F900B3C19A /* NotificationsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsCoordinator.swift; sourceTree = "<group>"; };
CE0457972632E47B00B3C19A /* NWSAlertCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NWSAlertCell.swift; sourceTree = "<group>"; }; CE0DB579267248580087E07A /* OneWeatherAnalytics.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OneWeatherAnalytics.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CE13B76226246743007CBD4D /* CCPAHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CCPAHelper.swift; sourceTree = "<group>"; }; CE13B76226246743007CBD4D /* CCPAHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CCPAHelper.swift; sourceTree = "<group>"; };
CE13B7DC262478E7007CBD4D /* PSMLocationSDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PSMLocationSDK.xcframework; sourceTree = "<group>"; }; CE13B7DC262478E7007CBD4D /* PSMLocationSDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = PSMLocationSDK.xcframework; sourceTree = "<group>"; };
CE13B7F3262480B3007CBD4D /* StoriesNativeAd.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = StoriesNativeAd.xib; sourceTree = "<group>"; }; CE13B7F4262480B3007CBD4D /* NativeBannerContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeBannerContainerView.swift; sourceTree = "<group>"; };
CE13B7F4262480B3007CBD4D /* BRNativeBannerContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BRNativeBannerContainerView.swift; sourceTree = "<group>"; };
CE13B7F5262480B3007CBD4D /* StoriesNativeAdCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = StoriesNativeAdCell.xib; sourceTree = "<group>"; };
CE13B7F6262480B3007CBD4D /* StoriesNativeAdCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoriesNativeAdCell.swift; sourceTree = "<group>"; };
CE13B7F7262480B3007CBD4D /* NativeAdItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeAdItem.swift; sourceTree = "<group>"; }; CE13B7F7262480B3007CBD4D /* NativeAdItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeAdItem.swift; sourceTree = "<group>"; };
CE13B7F8262480B3007CBD4D /* StoriesLeftNativeAd.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = StoriesLeftNativeAd.xib; sourceTree = "<group>"; };
CE13B7F9262480B3007CBD4D /* BRNativeBannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BRNativeBannerView.swift; sourceTree = "<group>"; };
CE13B7FA262480B3007CBD4D /* StoriesNativeAd.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoriesNativeAd.swift; sourceTree = "<group>"; };
CE13B7FB262480B3007CBD4D /* NativeAdLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeAdLoader.swift; sourceTree = "<group>"; }; CE13B7FB262480B3007CBD4D /* NativeAdLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeAdLoader.swift; sourceTree = "<group>"; };
CE13B7FC262480B3007CBD4D /* BRNativeBannerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BRNativeBannerView.xib; sourceTree = "<group>"; }; CE13B7FC262480B3007CBD4D /* NativeBannerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NativeBannerView.xib; sourceTree = "<group>"; };
CE13B7FD262480B3007CBD4D /* BRMoPubAdView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BRMoPubAdView.h; sourceTree = "<group>"; }; CE13B7FD262480B3007CBD4D /* BRMoPubAdView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BRMoPubAdView.h; sourceTree = "<group>"; };
CE13B7FF262480B3007CBD4D /* A9BidObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = A9BidObject.swift; sourceTree = "<group>"; }; CE13B7FF262480B3007CBD4D /* A9BidObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = A9BidObject.swift; sourceTree = "<group>"; };
CE13B800262480B3007CBD4D /* A9Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = A9Cache.swift; sourceTree = "<group>"; }; CE13B800262480B3007CBD4D /* A9Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = A9Cache.swift; sourceTree = "<group>"; };
...@@ -412,17 +420,21 @@ ...@@ -412,17 +420,21 @@
CE578FE425FB415F00E8B85D /* LocationsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationsViewModel.swift; sourceTree = "<group>"; }; CE578FE425FB415F00E8B85D /* LocationsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationsViewModel.swift; sourceTree = "<group>"; };
CE6BE4932634170800626822 /* USStateCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = USStateCode.swift; sourceTree = "<group>"; }; CE6BE4932634170800626822 /* USStateCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = USStateCode.swift; sourceTree = "<group>"; };
CE6F5F0B263C8B3C00973137 /* SmartTextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextProvider.swift; sourceTree = "<group>"; }; CE6F5F0B263C8B3C00973137 /* SmartTextProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartTextProvider.swift; sourceTree = "<group>"; };
CE81A421266E289E00800EFF /* NativeAdView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeAdView.swift; sourceTree = "<group>"; };
CE849DB52638C33600DEFFBD /* OneWeatherNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OneWeatherNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; CE849DB52638C33600DEFFBD /* OneWeatherNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OneWeatherNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
CE849DB72638C33600DEFFBD /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; }; CE849DB72638C33600DEFFBD /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
CE849DB92638C33600DEFFBD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; CE849DB92638C33600DEFFBD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CE849DE82638C59800DEFFBD /* OneWeatherNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OneWeatherNotificationServiceExtension.entitlements; sourceTree = "<group>"; }; CE849DE82638C59800DEFFBD /* OneWeatherNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OneWeatherNotificationServiceExtension.entitlements; sourceTree = "<group>"; };
CE849E372638CE8000DEFFBD /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; }; CE849E372638CE8000DEFFBD /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
CE895F0E26393FD800214175 /* WeatherImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherImageProvider.swift; sourceTree = "<group>"; }; CE895F0E26393FD800214175 /* WeatherImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherImageProvider.swift; sourceTree = "<group>"; };
CE9C077F266A4768004197FC /* NativeMRECView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NativeMRECView.xib; sourceTree = "<group>"; };
CEBAC1C72638240800A89681 /* DeeplinksRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeeplinksRouter.swift; sourceTree = "<group>"; }; CEBAC1C72638240800A89681 /* DeeplinksRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeeplinksRouter.swift; sourceTree = "<group>"; };
CEC7D8ED2639FE2700B8836D /* OLInAppStoreManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OLInAppStoreManager.swift; sourceTree = "<group>"; }; CEC7D8ED2639FE2700B8836D /* OLInAppStoreManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OLInAppStoreManager.swift; sourceTree = "<group>"; };
CEC8FBAE2639756A0001A6BF /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; }; CEC8FBAE2639756A0001A6BF /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
CEC8FBB1263976240001A6BF /* OnboardingCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingCoordinator.swift; sourceTree = "<group>"; }; CEC8FBB1263976240001A6BF /* OnboardingCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingCoordinator.swift; sourceTree = "<group>"; };
CEC8FBB4263976400001A6BF /* OnboardingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewModel.swift; sourceTree = "<group>"; }; CEC8FBB4263976400001A6BF /* OnboardingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewModel.swift; sourceTree = "<group>"; };
CEEB3546266F5D9900E16F90 /* BannerAdCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerAdCell.swift; sourceTree = "<group>"; };
CEEB3548266F5DA900E16F90 /* MRECAdCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MRECAdCell.swift; sourceTree = "<group>"; };
CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BlendFIPSSource.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BlendFIPSSource.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DF826CF4702D9DCCB9A9DD71 /* Pods-1Weather.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-1Weather.release.xcconfig"; path = "Target Support Files/Pods-1Weather/Pods-1Weather.release.xcconfig"; sourceTree = "<group>"; }; DF826CF4702D9DCCB9A9DD71 /* Pods-1Weather.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-1Weather.release.xcconfig"; path = "Target Support Files/Pods-1Weather/Pods-1Weather.release.xcconfig"; sourceTree = "<group>"; };
FD761FE0D947B3A79121A941 /* Pods-OneWeatherNotificationServiceExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneWeatherNotificationServiceExtension.release.xcconfig"; path = "Target Support Files/Pods-OneWeatherNotificationServiceExtension/Pods-OneWeatherNotificationServiceExtension.release.xcconfig"; sourceTree = "<group>"; }; FD761FE0D947B3A79121A941 /* Pods-OneWeatherNotificationServiceExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneWeatherNotificationServiceExtension.release.xcconfig"; path = "Target Support Files/Pods-OneWeatherNotificationServiceExtension/Pods-OneWeatherNotificationServiceExtension.release.xcconfig"; sourceTree = "<group>"; };
...@@ -442,6 +454,7 @@ ...@@ -442,6 +454,7 @@
CD3884832657BBCC0070FD6F /* DelayedSaveStorage.framework in Frameworks */, CD3884832657BBCC0070FD6F /* DelayedSaveStorage.framework in Frameworks */,
CEEF4100265E47FF00425D8F /* BlendFIPSSource.framework in Frameworks */, CEEF4100265E47FF00425D8F /* BlendFIPSSource.framework in Frameworks */,
CD615F7E265523BD00B717DB /* OneWeatherCore.framework in Frameworks */, CD615F7E265523BD00B717DB /* OneWeatherCore.framework in Frameworks */,
CE0DB57A267248580087E07A /* OneWeatherAnalytics.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -450,7 +463,7 @@ ...@@ -450,7 +463,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
CE849E382638CE8000DEFFBD /* UserNotifications.framework in Frameworks */, CE849E382638CE8000DEFFBD /* UserNotifications.framework in Frameworks */,
C27F92C189A9C9E637AF6C3A /* Pods_OneWeatherNotificationServiceExtension.framework in Frameworks */, CE0DB57C26724C240087E07A /* Pods_OneWeatherNotificationServiceExtension.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -774,7 +787,6 @@ ...@@ -774,7 +787,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CDA5542725EF734200A2E08C /* TodayCellFactory.swift */, CDA5542725EF734200A2E08C /* TodayCellFactory.swift */,
CD822FFD25D6976F00A05501 /* AdCell.swift */,
CD822FF425D6817000A05501 /* TodayForecastCell.swift */, CD822FF425D6817000A05501 /* TodayForecastCell.swift */,
CD15DB4125DA806C00024727 /* TodayForecastTimePeriodCell.swift */, CD15DB4125DA806C00024727 /* TodayForecastTimePeriodCell.swift */,
CD82300125D69DB900A05501 /* TodayConditions */, CD82300125D69DB900A05501 /* TodayConditions */,
...@@ -817,12 +829,6 @@ ...@@ -817,12 +829,6 @@
CD8B6080263817A00055CB3F /* Recovered References */ = { CD8B6080263817A00055CB3F /* Recovered References */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
87D815AE2636E6BF0015A6D1 /* NWSForecastOfficeTableViewCell.swift */,
87D815842636CFFD0015A6D1 /* NWSAlertViewController.swift */,
CE0457922632B3DD00B3C19A /* NotificationsViewController.swift */,
87D815B02636ED850015A6D1 /* NWSAlertCellFactory.swift */,
87D815B22636F2040015A6D1 /* NWSAlertInfoBlockTableViewCell.swift */,
CE0457972632E47B00B3C19A /* NWSAlertCell.swift */,
); );
name = "Recovered References"; name = "Recovered References";
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -904,6 +910,7 @@ ...@@ -904,6 +910,7 @@
CDC0C7AE261310DB0030607A /* SharedCells */ = { CDC0C7AE261310DB0030607A /* SharedCells */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CEEB354A266F687300E16F90 /* AdCells */,
CD86246325E66E6B0097F3FB /* PrecipCell */, CD86246325E66E6B0097F3FB /* PrecipCell */,
CD86245B25E646000097F3FB /* SunPhaseCell */, CD86245B25E646000097F3FB /* SunPhaseCell */,
CDC6126025E8DA2900188DA7 /* MoonPhaseCell */, CDC6126025E8DA2900188DA7 /* MoonPhaseCell */,
...@@ -966,6 +973,9 @@ ...@@ -966,6 +973,9 @@
CDD0F1E3257240F300CF5017 /* Fonts */ = { CDD0F1E3257240F300CF5017 /* Fonts */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
87B66BF02667AF1900B9A59A /* SF-Compact-Display-Light.otf */,
87B66BEB2667A44F00B9A59A /* SF-Compact-Display-Regular.otf */,
87B66BEA2667A44F00B9A59A /* SF-Compact-Display-Semibold.otf */,
CDD0F1E42572425200CF5017 /* SF-Pro.ttf */, CDD0F1E42572425200CF5017 /* SF-Pro.ttf */,
); );
path = Fonts; path = Fonts;
...@@ -1041,16 +1051,10 @@ ...@@ -1041,16 +1051,10 @@
CE13B7F2262480B3007CBD4D /* Native */ = { CE13B7F2262480B3007CBD4D /* Native */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CE13B7F3262480B3007CBD4D /* StoriesNativeAd.xib */, CE81A420266E288C00800EFF /* NativeAdViews */,
CE13B7F4262480B3007CBD4D /* BRNativeBannerContainerView.swift */, CE13B7F4262480B3007CBD4D /* NativeBannerContainerView.swift */,
CE13B7F5262480B3007CBD4D /* StoriesNativeAdCell.xib */,
CE13B7F6262480B3007CBD4D /* StoriesNativeAdCell.swift */,
CE13B7F7262480B3007CBD4D /* NativeAdItem.swift */, CE13B7F7262480B3007CBD4D /* NativeAdItem.swift */,
CE13B7F8262480B3007CBD4D /* StoriesLeftNativeAd.xib */,
CE13B7F9262480B3007CBD4D /* BRNativeBannerView.swift */,
CE13B7FA262480B3007CBD4D /* StoriesNativeAd.swift */,
CE13B7FB262480B3007CBD4D /* NativeAdLoader.swift */, CE13B7FB262480B3007CBD4D /* NativeAdLoader.swift */,
CE13B7FC262480B3007CBD4D /* BRNativeBannerView.xib */,
); );
path = Native; path = Native;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -1101,6 +1105,16 @@ ...@@ -1101,6 +1105,16 @@
path = Cells; path = Cells;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
CE81A420266E288C00800EFF /* NativeAdViews */ = {
isa = PBXGroup;
children = (
CE81A421266E289E00800EFF /* NativeAdView.swift */,
CE13B7FC262480B3007CBD4D /* NativeBannerView.xib */,
CE9C077F266A4768004197FC /* NativeMRECView.xib */,
);
path = NativeAdViews;
sourceTree = "<group>";
};
CE849DB62638C33600DEFFBD /* OneWeatherNotificationServiceExtension */ = { CE849DB62638C33600DEFFBD /* OneWeatherNotificationServiceExtension */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
...@@ -1157,9 +1171,20 @@ ...@@ -1157,9 +1171,20 @@
path = Onboarding; path = Onboarding;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
CEEB354A266F687300E16F90 /* AdCells */ = {
isa = PBXGroup;
children = (
CD822FFD25D6976F00A05501 /* AdCell.swift */,
CEEB3546266F5D9900E16F90 /* BannerAdCell.swift */,
CEEB3548266F5DA900E16F90 /* MRECAdCell.swift */,
);
path = AdCells;
sourceTree = "<group>";
};
DBFD169AA2AA6A3CB5B68BB5 /* Frameworks */ = { DBFD169AA2AA6A3CB5B68BB5 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CE0DB579267248580087E07A /* OneWeatherAnalytics.framework */,
CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */, CEEF40FF265E47FF00425D8F /* BlendFIPSSource.framework */,
CD3884822657BBCC0070FD6F /* DelayedSaveStorage.framework */, CD3884822657BBCC0070FD6F /* DelayedSaveStorage.framework */,
CD3884542657BA8B0070FD6F /* CoreDataStorage.framework */, CD3884542657BA8B0070FD6F /* CoreDataStorage.framework */,
...@@ -1213,6 +1238,7 @@ ...@@ -1213,6 +1238,7 @@
CE849DB22638C33600DEFFBD /* Frameworks */, CE849DB22638C33600DEFFBD /* Frameworks */,
CE849DB32638C33600DEFFBD /* Resources */, CE849DB32638C33600DEFFBD /* Resources */,
CE849E362638CE6300DEFFBD /* Run Script: set build number */, CE849E362638CE6300DEFFBD /* Run Script: set build number */,
CE0DB57E26724C240087E07A /* Embed Frameworks */,
); );
buildRules = ( buildRules = (
); );
...@@ -1269,12 +1295,13 @@ ...@@ -1269,12 +1295,13 @@
CDD75F0D25DE68B10099ACDB /* Localizable.strings in Resources */, CDD75F0D25DE68B10099ACDB /* Localizable.strings in Resources */,
87C171ED25FF79CC00DA3464 /* LocalConfig.plist in Resources */, 87C171ED25FF79CC00DA3464 /* LocalConfig.plist in Resources */,
CE376C98261EE484000B1159 /* LaunchScreen.storyboard in Resources */, CE376C98261EE484000B1159 /* LaunchScreen.storyboard in Resources */,
CE13B813262480B3007CBD4D /* StoriesLeftNativeAd.xib in Resources */, CE13B817262480B3007CBD4D /* NativeBannerView.xib in Resources */,
CE13B817262480B3007CBD4D /* BRNativeBannerView.xib in Resources */, 87B66BEC2667A45800B9A59A /* SF-Compact-Display-Semibold.otf in Resources */,
CE13B80E262480B3007CBD4D /* StoriesNativeAd.xib in Resources */,
CE13B88F26248A77007CBD4D /* GoogleService-Info-Staging.plist in Resources */, CE13B88F26248A77007CBD4D /* GoogleService-Info-Staging.plist in Resources */,
87B66BF12667AF1C00B9A59A /* SF-Compact-Display-Light.otf in Resources */,
87B66BED2667A45B00B9A59A /* SF-Compact-Display-Regular.otf in Resources */,
CE9C0780266A4768004197FC /* NativeMRECView.xib in Resources */,
CE13B88E26248A77007CBD4D /* GoogleService-Info-Production.plist in Resources */, CE13B88E26248A77007CBD4D /* GoogleService-Info-Production.plist in Resources */,
CE13B810262480B3007CBD4D /* StoriesNativeAdCell.xib in Resources */,
CD1237CC255D5C5C00C98139 /* Assets.xcassets in Resources */, CD1237CC255D5C5C00C98139 /* Assets.xcassets in Resources */,
CD822FFA25D6890900A05501 /* OneWeatherColorsAsset.xcassets in Resources */, CD822FFA25D6890900A05501 /* OneWeatherColorsAsset.xcassets in Resources */,
); );
...@@ -1464,17 +1491,16 @@ ...@@ -1464,17 +1491,16 @@
CDE2BF222609D4250085C930 /* ForecastWindSpeedCell.swift in Sources */, CDE2BF222609D4250085C930 /* ForecastWindSpeedCell.swift in Sources */,
CD866A6C260F676400E96A5C /* SettingsDetailsCellFactory.swift in Sources */, CD866A6C260F676400E96A5C /* SettingsDetailsCellFactory.swift in Sources */,
CDDE8D7F262EED4D00267931 /* MapLegendWeatherView.swift in Sources */, CDDE8D7F262EED4D00267931 /* MapLegendWeatherView.swift in Sources */,
CE13B815262480B3007CBD4D /* StoriesNativeAd.swift in Sources */,
87C171F425FF7A4000DA3464 /* PopularCitiesManager.swift in Sources */, 87C171F425FF7A4000DA3464 /* PopularCitiesManager.swift in Sources */,
CD67616A262575CD0079D273 /* MapLegendGradientView.swift in Sources */, CD67616A262575CD0079D273 /* MapLegendGradientView.swift in Sources */,
CD593BCC2608A4F200C93428 /* ForecastDailyCell.swift in Sources */, CD593BCC2608A4F200C93428 /* ForecastDailyCell.swift in Sources */,
CD866A72260F6A5300E96A5C /* SettingsDetailsCell.swift in Sources */, CD866A72260F6A5300E96A5C /* SettingsDetailsCell.swift in Sources */,
CD6761802625B0F50079D273 /* RadarLayerCell.swift in Sources */, CD6761802625B0F50079D273 /* RadarLayerCell.swift in Sources */,
CE13B80F262480B3007CBD4D /* BRNativeBannerContainerView.swift in Sources */, CE13B80F262480B3007CBD4D /* NativeBannerContainerView.swift in Sources */,
CD6761842625B6A10079D273 /* RadarLayersCellFactory.swift in Sources */, CD6761842625B6A10079D273 /* RadarLayersCellFactory.swift in Sources */,
CD67617C2625A60B0079D273 /* MapLayersDismissAnimator.swift in Sources */, CD67617C2625A60B0079D273 /* MapLayersDismissAnimator.swift in Sources */,
CE13B814262480B3007CBD4D /* BRNativeBannerView.swift in Sources */,
CD18728B2624763000AFEDAA /* MapLegendView.swift in Sources */, CD18728B2624763000AFEDAA /* MapLegendView.swift in Sources */,
CEEB3549266F5DA900E16F90 /* MRECAdCell.swift in Sources */,
CE13B818262480B3007CBD4D /* A9BidObject.swift in Sources */, CE13B818262480B3007CBD4D /* A9BidObject.swift in Sources */,
CDD0F1E82572429E00CF5017 /* AppFont.swift in Sources */, CDD0F1E82572429E00CF5017 /* AppFont.swift in Sources */,
CDC6124F25E7964700188DA7 /* TodayDayTimesCell.swift in Sources */, CDC6124F25E7964700188DA7 /* TodayDayTimesCell.swift in Sources */,
...@@ -1495,12 +1521,12 @@ ...@@ -1495,12 +1521,12 @@
CD39F2F225DE94C4009FE398 /* SunPhaseCell.swift in Sources */, CD39F2F225DE94C4009FE398 /* SunPhaseCell.swift in Sources */,
CD6B304325726AD1004B34B3 /* DefaultTheme.swift in Sources */, CD6B304325726AD1004B34B3 /* DefaultTheme.swift in Sources */,
CEC8FBB2263976240001A6BF /* OnboardingCoordinator.swift in Sources */, CEC8FBB2263976240001A6BF /* OnboardingCoordinator.swift in Sources */,
CEEB3547266F5D9900E16F90 /* BannerAdCell.swift in Sources */,
CD8B60B626381E0F0055CB3F /* AdsUserDefaultsWrapper.swift in Sources */, CD8B60B626381E0F0055CB3F /* AdsUserDefaultsWrapper.swift in Sources */,
CD9B6B1425DBCDE2001D9B80 /* GraphView.swift in Sources */, CD9B6B1425DBCDE2001D9B80 /* GraphView.swift in Sources */,
CD866A6F260F67F200E96A5C /* SettingsDetailsViewModel.swift in Sources */, CD866A6F260F67F200E96A5C /* SettingsDetailsViewModel.swift in Sources */,
CD71709025FA317700A63C27 /* ForecastTimePeriodView.swift in Sources */, CD71709025FA317700A63C27 /* ForecastTimePeriodView.swift in Sources */,
CE13B812262480B3007CBD4D /* NativeAdItem.swift in Sources */, CE13B812262480B3007CBD4D /* NativeAdItem.swift in Sources */,
CE13B811262480B3007CBD4D /* StoriesNativeAdCell.swift in Sources */,
CD37D3E5260CB05C002669D6 /* MenuFooterView.swift in Sources */, CD37D3E5260CB05C002669D6 /* MenuFooterView.swift in Sources */,
CDE18DD825D16CB200C80ED9 /* NavigationCityButton.swift in Sources */, CDE18DD825D16CB200C80ED9 /* NavigationCityButton.swift in Sources */,
CDAD97B1262042B2007FCFB1 /* MapButton.swift in Sources */, CDAD97B1262042B2007FCFB1 /* MapButton.swift in Sources */,
...@@ -1565,6 +1591,7 @@ ...@@ -1565,6 +1591,7 @@
CDDE8D7C262EED3C00267931 /* MapLegendSevereView.swift in Sources */, CDDE8D7C262EED3C00267931 /* MapLegendSevereView.swift in Sources */,
CD6761882625C3360079D273 /* RadarViewModel.swift in Sources */, CD6761882625C3360079D273 /* RadarViewModel.swift in Sources */,
CDF8F12A262089A200DB384A /* MapTimeView.swift in Sources */, CDF8F12A262089A200DB384A /* MapTimeView.swift in Sources */,
CE81A422266E289E00800EFF /* NativeAdView.swift in Sources */,
CE13B81D262480B3007CBD4D /* BRMoPubAdView.m in Sources */, CE13B81D262480B3007CBD4D /* BRMoPubAdView.m in Sources */,
CD37D3DE260C9E37002669D6 /* MenuCell.swift in Sources */, CD37D3DE260C9E37002669D6 /* MenuCell.swift in Sources */,
CD822FFE25D6976F00A05501 /* AdCell.swift in Sources */, CD822FFE25D6976F00A05501 /* AdCell.swift in Sources */,
......
...@@ -125,17 +125,11 @@ public class AdManager { ...@@ -125,17 +125,11 @@ public class AdManager {
a9Cache.addToPreload(placementName: placementNameTodayBanner, adType: .banner, count: 1) a9Cache.addToPreload(placementName: placementNameTodayBanner, adType: .banner, count: 1)
a9Cache.addToPreload(placementName: placementNameTodaySquare, adType: .square, count: 1) a9Cache.addToPreload(placementName: placementNameTodaySquare, adType: .square, count: 1)
a9Cache.addToPreload(placementName: placementNameDiscussionSquare, adType: .square, count: 1)
a9Cache.addToPreload(placementName: placementNameExtendedSquare, adType: .square, count: 1)
a9Cache.addToPreload(placementName: placementName12WeekInterstitial, adType: .interstitial, count: 1)
a9Cache.addToPreload(placementName: placementNameForecastHourlyBanner, adType: .banner, count: 1) a9Cache.addToPreload(placementName: placementNameForecastHourlyBanner, adType: .banner, count: 1)
a9Cache.addToPreload(placementName: placementNameForecastHourlySquare, adType: .square, count: 1) a9Cache.addToPreload(placementName: placementNameForecastHourlySquare, adType: .square, count: 1)
a9Cache.addToPreload(placementName: placementNameForecastExtendedBanner, adType: .banner, count: 1) a9Cache.addToPreload(placementName: placementNameForecastDailyBanner, adType: .banner, count: 1)
a9Cache.addToPreload(placementName: placementNameForecastExtendedSquare, adType: .square, count: 1) a9Cache.addToPreload(placementName: placementNameForecastDailySquare, adType: .square, count: 1)
a9Cache.addToPreload(placementName: placementNameForecast12WeekSquare, adType: .square, count: 1) a9Cache.addToPreload(placementName: placementNameNWSAlertBanner, adType: .banner, count: 1)
a9Cache.addToPreload(placementName: placementNamePrecipitationBanner, adType: .banner, count: 1)
a9Cache.addToPreload(placementName: placementNameRadarInterstitial, adType: .interstitial, count: 1)
a9Cache.addToPreload(placementName: placementNameSunMoonBanner, adType: .banner, count: 1)
a9Cache.startPreloadingBids() a9Cache.startPreloadingBids()
} }
......
...@@ -12,19 +12,28 @@ import UIKit ...@@ -12,19 +12,28 @@ import UIKit
import OneWeatherAnalytics import OneWeatherAnalytics
import OneWeatherCore import OneWeatherCore
@objc
public protocol AdViewDelegate: AnyObject { public protocol AdViewDelegate: AnyObject {
func succeeded(adView: AdView) func succeeded(adView: AdView, hadAdBefore: Bool)
func failed(adView: AdView) func failed(adView: AdView, hadAdBefore: Bool)
func closeButtonTapped(adView: AdView) func closeButtonTapped(adView: AdView)
/// Return the view controller, that will present the interstitial. /// Return the view controller, that will present the interstitial.
func adTopViewController() -> UIViewController func adTopViewController() -> UIViewController?
}
// MARK: - Default methods implementation
extension AdViewDelegate {
func closeButtonTapped(adView: AdView) {
// do nothing
}
func adTopViewController() -> UIViewController? {
return nil
}
} }
@objcMembers @objcMembers
public class AdView: UIView { public class AdView: UIView {
// MARK: - Private & Internal // MARK: - Private & Internal
private var bannerView: BRNativeBannerContainerView? private var bannerView: NativeBannerContainerView?
private lazy var autorefreshScheduler: Scheduler = { private lazy var autorefreshScheduler: Scheduler = {
return Scheduler(with: logName, interval: 0, onlyCountTimeWhenRunning: true) { [weak self] in return Scheduler(with: logName, interval: 0, onlyCountTimeWhenRunning: true) { [weak self] in
self?.requestAd(startAutorefresh: false) self?.requestAd(startAutorefresh: false)
...@@ -129,7 +138,7 @@ public class AdView: UIView { ...@@ -129,7 +138,7 @@ public class AdView: UIView {
log.warning("failed to guess the top view controller.") log.warning("failed to guess the top view controller.")
return return
} }
bannerView = BRNativeBannerContainerView(adUnitId: placement.adUnitId, rootViewController: topViewController) bannerView = NativeBannerContainerView(adUnitId: placement.adUnitId, adType: adType, rootViewController: topViewController)
if let bannerView = bannerView { if let bannerView = bannerView {
...@@ -323,25 +332,28 @@ extension AdView { ...@@ -323,25 +332,28 @@ extension AdView {
} }
} }
extension AdView: BRNativeBannerContainerViewDelegate { extension AdView: NativeBannerContainerViewDelegate {
func adLoader(_ adLoader: GADAdLoader, didReceived bannerView: GAMBannerView) { func adLoader(_ adLoader: GADAdLoader, didReceived bannerView: GAMBannerView) {
log.info("ad request succeeded") log.info("ad request succeeded")
let hadAdBefore = adReady
adReady = true adReady = true
analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams) analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams)
self.delegate?.succeeded(adView: self) self.delegate?.succeeded(adView: self, hadAdBefore: hadAdBefore)
} }
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) { func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
log.info("ad request succeeded") log.info("ad request succeeded")
let hadAdBefore = adReady
adReady = true adReady = true
analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams) analytics(log: .ANALYTICS_AD_RECEIVED, params: self.analyticsParams)
self.delegate?.succeeded(adView: self) self.delegate?.succeeded(adView: self, hadAdBefore: hadAdBefore)
} }
public func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) { public func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
log.error("ad request failed") log.error("ad request failed")
let hadAdBefore = adReady
adReady = false adReady = false
self.delegate?.failed(adView: self) self.delegate?.failed(adView: self, hadAdBefore: hadAdBefore)
} }
} }
......
...@@ -16,16 +16,11 @@ public struct AdConfig: Codable { ...@@ -16,16 +16,11 @@ public struct AdConfig: Codable {
public var a9MaxCachedPerPlacement: UInt public var a9MaxCachedPerPlacement: UInt
public var placements: [AdPlacementName: AdPlacement]? public var placements: [AdPlacementName: AdPlacement]?
public var nativePlacements: [AdPlacementName: NativeAdPlacement]?
public func placement(named name:String) -> AdPlacement? { public func placement(named name:String) -> AdPlacement? {
return placements?[name] return placements?[name]
} }
public func nativePlacement(named name:String) -> NativeAdPlacement? {
return nativePlacements?[name]
}
struct CodingKeys: CodingKey { struct CodingKeys: CodingKey {
var stringValue: String var stringValue: String
init(stringValue: String) { init(stringValue: String) {
...@@ -89,8 +84,7 @@ extension AdConfig: Equatable { ...@@ -89,8 +84,7 @@ extension AdConfig: Equatable {
public static func == (lhs: AdConfig, rhs: AdConfig) -> Bool { public static func == (lhs: AdConfig, rhs: AdConfig) -> Bool {
return lhs.adsEnabled == rhs.adsEnabled && return lhs.adsEnabled == rhs.adsEnabled &&
lhs.a9RefreshRate == rhs.a9RefreshRate && lhs.a9RefreshRate == rhs.a9RefreshRate &&
lhs.placements == rhs.placements && lhs.placements == rhs.placements
lhs.nativePlacements == rhs.nativePlacements
} }
} }
...@@ -104,20 +98,6 @@ extension ContentUrlConfig: Equatable { ...@@ -104,20 +98,6 @@ extension ContentUrlConfig: Equatable {
} }
} }
public struct NativeAdPlacement: Codable {
public var name: String
public var adUnitId: String
public var refreshInterval: TimeInterval
public var interstitialScreenCount: Int?
enum CodingKeys: String, CodingKey {
case name
case adUnitId = "ad_unit_id"
case refreshInterval = "refresh_interval"
case interstitialScreenCount = "interstitial_screen_count"
}
}
public struct AdPlacement: Codable { public struct AdPlacement: Codable {
public var name: String public var name: String
public var adUnitId: String public var adUnitId: String
...@@ -142,12 +122,3 @@ extension AdPlacement: Equatable { ...@@ -142,12 +122,3 @@ extension AdPlacement: Equatable {
lhs.refreshInterval == rhs.refreshInterval lhs.refreshInterval == rhs.refreshInterval
} }
} }
extension NativeAdPlacement: Equatable {
public static func == (lhs: NativeAdPlacement, rhs: NativeAdPlacement) -> Bool {
return lhs.name == rhs.name &&
lhs.adUnitId == rhs.adUnitId &&
lhs.refreshInterval == rhs.refreshInterval &&
lhs.interstitialScreenCount == rhs.interstitialScreenCount
}
}
...@@ -15,22 +15,17 @@ extension Notification.Name { ...@@ -15,22 +15,17 @@ extension Notification.Name {
public typealias AdPlacementName = String public typealias AdPlacementName = String
public let placementNameTodayBanner: AdPlacementName = "1W_iOS_Native_Banner_ForD_ATF" //TODO: wrong? public let placementNameTodayBanner: AdPlacementName = "today_banner"
public let placementNameTodaySquare: AdPlacementName = "1W_iOS_Native_MREC_Today_BTF2" public let placementNameTodaySquare: AdPlacementName = "today_square"
public let placementNameDiscussionSquare: AdPlacementName = "1W_iOS_Native_MREC_Forecast_discussion" public let placementNameForecastHourlyBanner: AdPlacementName = "forecast_hourly_banner"
public let placementNameExtendedSquare: AdPlacementName = "1W_iOS_Native_MREC_Forecast_discussion" // TODO: wrong? public let placementNameForecastHourlySquare: AdPlacementName = "forecast_hourly_square"
public let placementName12WeekInterstitial: AdPlacementName = "1W_iOS_Int" //TODO: definitely wrong public let placementNameForecastDailyBanner: AdPlacementName = "forecast_daily_banner"
public let placementNameForecastHourlyBanner: AdPlacementName = "1W_iOS_Native_Banner_Hourly_ATF" public let placementNameForecastDailySquare: AdPlacementName = "forecast_daily_square"
public let placementNameForecastHourlySquare: AdPlacementName = "1W_iOS_Native_MREC_Forecast_Hourly_BTF1" public let placementNameNWSAlertBanner: AdPlacementName = "nws_alert_banner"
public let placementNameForecastExtendedBanner: AdPlacementName = "1W_iOS_Native_Banner_ForD_ATF" // TODO: definitely wrong
public let placementNameForecastExtendedSquare: AdPlacementName = "1W_iOS_Native_MREC_Forecast_discussion" // TODO: definitely wrong
public let placementNameForecast12WeekSquare: AdPlacementName = "1W_iOS_Native_MREC_Today_Details" //TODO: definitely wrong
public let placementNamePrecipitationBanner: AdPlacementName = "1W_iOS_Native_Banner_Precipitation_ATF"
public let placementNameRadarInterstitial: AdPlacementName = "1W_iOS_Int" //TODO: definitely wrong
public let placementNameSunMoonBanner: AdPlacementName = "1W_iOS_Native_Banner_Sunmoon_ATF"
public class AdConfigManager: NSObject { public class AdConfigManager: NSObject {
@objc public static let shared = AdConfigManager() @objc
public static let shared = AdConfigManager()
private let configManager: ConfigManager private let configManager: ConfigManager
private init(configManager: ConfigManager? = nil) { private init(configManager: ConfigManager? = nil) {
......
//
// BRNativeBannerView.swift
// BaconReader
//
// Created by Rishab Dutta on 24/07/20.
// Copyright © 2020 OneLouder Apps. All rights reserved.
//
import Foundation
import GoogleMobileAds
class BRNativeBannerView: GADNativeAdView {
class func instantiateWithXib() -> BRNativeBannerView? {
let nib = UINib(nibName: "\(BRNativeBannerView.self)", bundle: nil)
let bView = nib.instantiate(withOwner: self, options: nil).first as? BRNativeBannerView
return bView
}
var nativeAdItem: NativeAdItem? {
didSet {
nativeAd = nativeAdItem?.nativeAd
setupView()
}
}
private func setupView() {
(headlineView as? UILabel)?.text = nativeAd?.headline
(iconView as? UIImageView)?.image = nativeAd?.icon?.image
(advertiserView as? UILabel)?.text = nativeAd?.advertiser
(callToActionView as? UILabel)?.text = nativeAd?.callToAction
}
}
...@@ -20,8 +20,8 @@ final class NativeAdItem: NSObject { ...@@ -20,8 +20,8 @@ final class NativeAdItem: NSObject {
case banner case banner
} }
private var placement: NativeAdPlacement? { private var placement: AdPlacement? {
return AdConfigManager.shared.adConfig.nativePlacements?.filter({ $0.value.adUnitId == adUnitId }).first?.value return AdConfigManager.shared.adConfig.placements?.filter({ $0.value.adUnitId == adUnitId }).first?.value
} }
private var analyticsParams: [AnalyticsParameter: Any] { private var analyticsParams: [AnalyticsParameter: Any] {
...@@ -62,9 +62,6 @@ final class NativeAdItem: NSObject { ...@@ -62,9 +62,6 @@ final class NativeAdItem: NSObject {
} }
func placementName() -> AdPlacementName? { func placementName() -> AdPlacementName? {
if let nativePlacement = AdConfigManager.shared.adConfig.nativePlacements?.filter({ $0.value.adUnitId == adUnitId }).first {
return nativePlacement.key
}
if let bannerPlacement = AdConfigManager.shared.adConfig.placements?.filter({ $0.value.adUnitId == adUnitId }).first { if let bannerPlacement = AdConfigManager.shared.adConfig.placements?.filter({ $0.value.adUnitId == adUnitId }).first {
return bannerPlacement.key return bannerPlacement.key
} }
......
//
// NativeAdView.swift
// 1Weather
//
// Created by Demid Merzlyakov on 07.06.2021.
//
import Foundation
import GoogleMobileAds
class NativeAdView: GADNativeAdView {
@IBOutlet weak var sponsoredLabel: UILabel?
@IBOutlet weak var adChoicesViewCustomOutlet: GADAdChoicesView?
var headlineLabel: UILabel? {
headlineView as? UILabel
}
var advertiserLabel: UILabel? {
advertiserView as? UILabel
}
var bodyLabel: UILabel? {
bodyView as? UILabel
}
var iconImageView: UIImageView? {
iconView as? UIImageView
}
var callToActionLabel: UILabel? {
callToActionView as? UILabel
}
var mainImageView: UIImageView? {
imageView as? UIImageView
}
public class func instantiateWithXib(adType: AdType) -> NativeAdView? {
var xibName: String!
switch adType {
case .banner:
xibName = "NativeBannerView"
case .square:
xibName = "NativeMRECView"
case .interstitial:
assertionFailure("Incorrect ad type - interstitial")
return nil
}
let nib = UINib(nibName: xibName, bundle: nil)
let bView = nib.instantiate(withOwner: self, options: nil).first as? NativeAdView
bView?.setupPostXib()
return bView
}
func setupPostXib() {
let currentTheme = ThemeManager.currentTheme
callToActionLabel?.backgroundColor = currentTheme.nativeAdCallToActionColor
callToActionLabel?.layer.cornerRadius = 2
callToActionLabel?.clipsToBounds = true
headlineLabel?.textColor = currentTheme.primaryTextColor
advertiserLabel?.textColor = currentTheme.primaryTextColor
self.adChoicesView = self.adChoicesViewCustomOutlet
sponsoredLabel?.text = "ads.native.sponsored".localized()
sponsoredLabel?.textColor = currentTheme.primaryTextColor
bodyLabel?.textColor = currentTheme.secondaryTextColor
setupFonts()
}
private func setupFonts() {
callToActionLabel?.font = AppFont.SFCompactDisplay.regular(size: 10)
sponsoredLabel?.font = AppFont.SFCompactDisplay.regular(size: 10)
headlineLabel?.font = AppFont.SFCompactDisplay.semibold(size: 18)
advertiserLabel?.font = AppFont.SFCompactDisplay.regular(size: 12)
callToActionLabel?.font = AppFont.SFCompactDisplay.light(size: 10)
bodyLabel?.font = AppFont.SFCompactDisplay.regular(size: 10)
}
var nativeAdItem: NativeAdItem? {
willSet {
self.adChoicesView = self.adChoicesViewCustomOutlet
}
didSet {
nativeAd = nativeAdItem?.nativeAd
setupView()
}
}
private func setupView() {
headlineLabel?.text = nativeAd?.headline
iconImageView?.image = nativeAd?.icon?.image
advertiserLabel?.text = nativeAd?.advertiser
callToActionLabel?.text = nativeAd?.callToAction
bodyLabel?.text = nativeAd?.body
mainImageView?.image = nativeAd?.images?.first?.image
setupPostXib()
}
}
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/> <device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<customFonts key="customFonts">
<array key="SF-Pro.ttf">
<string>SFPro-Regular</string>
<string>SFPro-Semibold</string>
</array>
</customFonts>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="BRNativeBannerView" customModule="BaconReader" customModuleProvider="target"> <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="NativeAdView" customModule="_Weather" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="50"/> <rect key="frame" x="0.0" y="0.0" width="320" height="64"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="eaA-5a-cX3"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="eaA-5a-cX3">
<rect key="frame" x="0.0" y="0.0" width="60" height="50"/> <rect key="frame" x="12" y="9" width="40" height="40"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="60" id="IvN-D3-kN1"/> <constraint firstAttribute="width" constant="40" id="6ZZ-jb-7ZN"/>
<constraint firstAttribute="height" constant="40" id="ant-Au-KVU"/>
</constraints> </constraints>
</imageView> </imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" placeholderIntrinsicWidth="148" placeholderIntrinsicHeight="15" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VsC-Xg-upl"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" placeholderIntrinsicWidth="148" placeholderIntrinsicHeight="15" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="149" translatesAutoresizingMaskIntoConstraints="NO" id="VsC-Xg-upl">
<rect key="frame" x="68" y="8" width="164" height="15"/> <rect key="frame" x="64" y="11" width="148" height="15"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/> <fontDescription key="fontDescription" name="SFPro-Semibold" family="SF Pro" pointSize="18"/>
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" placeholderIntrinsicWidth="148" placeholderIntrinsicHeight="12" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lTc-8y-qle"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" placeholderIntrinsicWidth="148" placeholderIntrinsicHeight="12" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lTc-8y-qle">
<rect key="frame" x="68" y="27" width="164" height="15"/> <rect key="frame" x="64" y="29" width="167" height="12"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/> <fontDescription key="fontDescription" name="SFPro-Regular" family="SF Pro" pointSize="12"/>
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ugd-1P-6ea"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ugd-1P-6ea">
<rect key="frame" x="240" y="0.0" width="80" height="50"/> <rect key="frame" x="239" y="27" width="69" height="22"/>
<color key="backgroundColor" red="0.066666666666666666" green="0.49803921568627452" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.066666666666666666" green="0.49803921568627452" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="80" id="cDN-Y8-VOr"/> <constraint firstAttribute="height" constant="22" id="WS5-UR-JYL"/>
<constraint firstAttribute="width" constant="69" id="t8x-Db-p3Z"/>
</constraints> </constraints>
<fontDescription key="fontDescription" type="system" pointSize="12"/> <fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sponsored" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XLW-zy-iAT">
<rect key="frame" x="244" y="6" width="52" height="12"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" horizontalCompressionResistancePriority="1000" translatesAutoresizingMaskIntoConstraints="NO" id="28Q-DN-nbV" customClass="GADAdChoicesView">
<rect key="frame" x="300" y="7.5" width="8" height="9"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="8" id="I4w-tj-TCL"/>
<constraint firstAttribute="width" priority="250" constant="8" id="ag4-wU-uBL"/>
<constraint firstAttribute="height" constant="9" id="ltQ-ay-EqL"/>
</constraints>
</view>
</subviews> </subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints> <constraints>
<constraint firstItem="VsC-Xg-upl" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="8" id="8Dj-HX-wth"/> <constraint firstItem="eaA-5a-cX3" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="12" id="1rN-7b-aQR"/>
<constraint firstItem="VsC-Xg-upl" firstAttribute="leading" secondItem="eaA-5a-cX3" secondAttribute="trailing" constant="8" id="I0z-Nl-GLm"/> <constraint firstItem="eaA-5a-cX3" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="9" id="5pq-Tc-Urj"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="eaA-5a-cX3" secondAttribute="bottom" id="Ixm-4U-KsW"/> <constraint firstItem="lTc-8y-qle" firstAttribute="leading" secondItem="VsC-Xg-upl" secondAttribute="leading" id="7F4-Td-70H"/>
<constraint firstItem="ugd-1P-6ea" firstAttribute="leading" secondItem="VsC-Xg-upl" secondAttribute="trailing" constant="8" id="JGt-cR-nRx"/> <constraint firstItem="VsC-Xg-upl" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="11" id="8Dj-HX-wth"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="lTc-8y-qle" secondAttribute="bottom" constant="8" id="JS0-89-xm1"/> <constraint firstItem="XLW-zy-iAT" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="VsC-Xg-upl" secondAttribute="trailing" constant="8" id="GKr-05-hYa"/>
<constraint firstItem="lTc-8y-qle" firstAttribute="top" secondItem="VsC-Xg-upl" secondAttribute="bottom" constant="4" id="NLk-O1-U3Q"/> <constraint firstItem="ugd-1P-6ea" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="VsC-Xg-upl" secondAttribute="trailing" constant="8" id="IOw-O0-6AH"/>
<constraint firstItem="eaA-5a-cX3" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="SdU-tC-7IC"/> <constraint firstItem="lTc-8y-qle" firstAttribute="top" secondItem="VsC-Xg-upl" secondAttribute="bottom" constant="3" id="Iil-e1-IEN"/>
<constraint firstItem="eaA-5a-cX3" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="Wmr-hd-DEw"/> <constraint firstAttribute="trailing" secondItem="28Q-DN-nbV" secondAttribute="trailing" constant="12" id="MSw-KS-ywK"/>
<constraint firstItem="lTc-8y-qle" firstAttribute="leading" secondItem="eaA-5a-cX3" secondAttribute="trailing" constant="8" id="Xon-27-Iwc"/> <constraint firstItem="XLW-zy-iAT" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="6" id="R8L-eY-ClU"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="ugd-1P-6ea" secondAttribute="bottom" id="ZpJ-el-ui6"/> <constraint firstAttribute="trailing" secondItem="ugd-1P-6ea" secondAttribute="trailing" constant="12" id="Z80-qh-oZo"/>
<constraint firstAttribute="trailing" secondItem="ugd-1P-6ea" secondAttribute="trailing" id="aR1-OF-dyw"/> <constraint firstItem="VsC-Xg-upl" firstAttribute="leading" secondItem="eaA-5a-cX3" secondAttribute="trailing" constant="12" id="hkh-dD-Vac"/>
<constraint firstItem="ugd-1P-6ea" firstAttribute="leading" secondItem="lTc-8y-qle" secondAttribute="trailing" constant="8" id="hrG-SE-D7R"/> <constraint firstAttribute="bottom" secondItem="ugd-1P-6ea" secondAttribute="bottom" constant="15" id="iEk-zr-gKO"/>
<constraint firstItem="ugd-1P-6ea" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="i9E-Fz-ouY"/> <constraint firstItem="ugd-1P-6ea" firstAttribute="leading" secondItem="lTc-8y-qle" secondAttribute="trailing" constant="8" id="qdU-J6-PCw"/>
<constraint firstItem="28Q-DN-nbV" firstAttribute="centerY" secondItem="XLW-zy-iAT" secondAttribute="centerY" id="y1m-tp-3KF"/>
<constraint firstItem="28Q-DN-nbV" firstAttribute="leading" secondItem="XLW-zy-iAT" secondAttribute="trailing" constant="4" id="ygk-Yg-8jR"/>
</constraints> </constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<connections> <connections>
<outlet property="adChoicesViewCustomOutlet" destination="28Q-DN-nbV" id="yYZ-Vw-lAB"/>
<outlet property="advertiserView" destination="lTc-8y-qle" id="zFU-6W-SBX"/> <outlet property="advertiserView" destination="lTc-8y-qle" id="zFU-6W-SBX"/>
<outlet property="callToActionView" destination="ugd-1P-6ea" id="VBG-Fk-Pn7"/> <outlet property="callToActionView" destination="ugd-1P-6ea" id="VBG-Fk-Pn7"/>
<outlet property="headlineView" destination="VsC-Xg-upl" id="pHO-sW-gXV"/> <outlet property="headlineView" destination="VsC-Xg-upl" id="pHO-sW-gXV"/>
<outlet property="iconView" destination="eaA-5a-cX3" id="4P6-sq-Gob"/> <outlet property="iconView" destination="eaA-5a-cX3" id="4P6-sq-Gob"/>
<outlet property="sponsoredLabel" destination="XLW-zy-iAT" id="EZ2-qJ-eFP"/>
</connections> </connections>
<point key="canvasLocation" x="214.49275362318843" y="-152.00892857142856"/> <point key="canvasLocation" x="214.49275362318843" y="-152.00892857142856"/>
</view> </view>
</objects> </objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document> </document>
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="GADNativeAdView"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="A8i-el-bXZ" customClass="NativeAdView" customModule="_Weather" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="300" height="250"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TNc-iz-mnZ">
<rect key="frame" x="0.0" y="0.0" width="300" height="155"/>
<constraints>
<constraint firstAttribute="height" constant="155" id="2of-WV-KVU"/>
<constraint firstAttribute="width" constant="300" id="fBU-Kp-e3s"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Headline" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ALU-9y-yCS">
<rect key="frame" x="10" y="160" width="280" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Body" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="b9r-uH-Qrr">
<rect key="frame" x="10" y="180" width="222" height="11"/>
<fontDescription key="fontDescription" type="system" pointSize="9"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="CTA" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7po-us-Uyw">
<rect key="frame" x="10" y="210" width="78" height="26"/>
<color key="backgroundColor" red="0.066666666669999999" green="0.49803921569999998" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="26" id="5wk-Js-TvA"/>
<constraint firstAttribute="width" constant="78" id="mQK-sj-eIi"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="k7n-sU-yPp">
<rect key="frame" x="236" y="184" width="54" height="54"/>
<constraints>
<constraint firstAttribute="width" constant="54" id="DaG-29-Yci"/>
<constraint firstAttribute="height" constant="54" id="Ol9-Ch-SAu"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="4vU-qI-YDI"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="k7n-sU-yPp" firstAttribute="leading" secondItem="b9r-uH-Qrr" secondAttribute="trailing" constant="4" id="42b-ug-6to"/>
<constraint firstItem="TNc-iz-mnZ" firstAttribute="leading" secondItem="A8i-el-bXZ" secondAttribute="leading" id="5EK-gf-w66"/>
<constraint firstItem="7po-us-Uyw" firstAttribute="leading" secondItem="A8i-el-bXZ" secondAttribute="leading" constant="10" id="5FJ-Je-u1p"/>
<constraint firstItem="b9r-uH-Qrr" firstAttribute="top" secondItem="ALU-9y-yCS" secondAttribute="bottom" id="7uv-BN-qIz"/>
<constraint firstAttribute="bottom" secondItem="7po-us-Uyw" secondAttribute="bottom" constant="14" id="Apu-0q-oJC"/>
<constraint firstAttribute="bottom" secondItem="k7n-sU-yPp" secondAttribute="bottom" constant="12" id="CRP-vK-rgT"/>
<constraint firstAttribute="trailing" secondItem="k7n-sU-yPp" secondAttribute="trailing" constant="10" id="IBC-YR-xho"/>
<constraint firstItem="b9r-uH-Qrr" firstAttribute="leading" secondItem="ALU-9y-yCS" secondAttribute="leading" id="aoN-Pv-cUM"/>
<constraint firstItem="ALU-9y-yCS" firstAttribute="leading" secondItem="A8i-el-bXZ" secondAttribute="leading" constant="10" id="dBl-Mj-Bmh"/>
<constraint firstItem="ALU-9y-yCS" firstAttribute="top" secondItem="TNc-iz-mnZ" secondAttribute="bottom" constant="5" id="j1x-NM-1zu"/>
<constraint firstAttribute="trailing" secondItem="TNc-iz-mnZ" secondAttribute="trailing" id="o1v-BR-AAi"/>
<constraint firstAttribute="trailing" secondItem="ALU-9y-yCS" secondAttribute="trailing" constant="10" id="tNs-jB-g7c"/>
<constraint firstItem="TNc-iz-mnZ" firstAttribute="top" secondItem="A8i-el-bXZ" secondAttribute="top" id="u0g-go-6RF"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="bodyView" destination="b9r-uH-Qrr" id="mHO-sW-gX7"/>
<outlet property="callToActionView" destination="7po-us-Uyw" id="VBG-Fk-Pn7"/>
<outlet property="headlineView" destination="ALU-9y-yCS" id="pHO-sW-gXV"/>
<outlet property="iconView" destination="k7n-sU-yPp" id="4P6-sq-Gob"/>
<outlet property="imageView" destination="TNc-iz-mnZ" id="TN6-iz-mnZ"/>
</connections>
<point key="canvasLocation" x="214.49275362318843" y="-94.419642857142847"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
// //
// BRNativeBannerContainerView.swift // NativeBannerContainerView.swift
// BaconReader // BaconReader
// //
// Created by Rishab Dutta on 24/07/20. // Created by Rishab Dutta on 24/07/20.
...@@ -10,7 +10,7 @@ import Foundation ...@@ -10,7 +10,7 @@ import Foundation
import GoogleMobileAds import GoogleMobileAds
import OneWeatherAnalytics import OneWeatherAnalytics
protocol BRNativeBannerContainerViewDelegate: AnyObject { protocol NativeBannerContainerViewDelegate: AnyObject {
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd)
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error)
...@@ -18,12 +18,13 @@ protocol BRNativeBannerContainerViewDelegate: AnyObject { ...@@ -18,12 +18,13 @@ protocol BRNativeBannerContainerViewDelegate: AnyObject {
func adLoader(_ adLoader: GADAdLoader, didReceived bannerView: GAMBannerView) func adLoader(_ adLoader: GADAdLoader, didReceived bannerView: GAMBannerView)
} }
class BRNativeBannerContainerView: UIView { class NativeBannerContainerView: UIView {
private let log = AdLogger(componentName: "BRNativeBannerContainerView") private let log = AdLogger(componentName: "NativeBannerContainerView")
private var adLoader: NativeAdLoader private var adLoader: NativeAdLoader
private let adType: AdType
weak var delegate: BRNativeBannerContainerViewDelegate? weak var delegate: NativeBannerContainerViewDelegate?
public var loggingAlias: String? { public var loggingAlias: String? {
didSet { didSet {
...@@ -31,7 +32,8 @@ class BRNativeBannerContainerView: UIView { ...@@ -31,7 +32,8 @@ class BRNativeBannerContainerView: UIView {
} }
} }
init(adUnitId: String, rootViewController: UIViewController) { init(adUnitId: String, adType: AdType, rootViewController: UIViewController) {
self.adType = adType
self.adLoader = NativeAdLoader(adUnitId: adUnitId, rootViewController: rootViewController, adTypes: [.native, .gamBanner]) self.adLoader = NativeAdLoader(adUnitId: adUnitId, rootViewController: rootViewController, adTypes: [.native, .gamBanner])
super.init(frame: .zero) super.init(frame: .zero)
self.adLoader.delegate = self self.adLoader.delegate = self
...@@ -47,15 +49,15 @@ class BRNativeBannerContainerView: UIView { ...@@ -47,15 +49,15 @@ class BRNativeBannerContainerView: UIView {
private func logNameUpdated() { private func logNameUpdated() {
if let loggingAlias = self.loggingAlias { if let loggingAlias = self.loggingAlias {
log.componentName = "BRNativeBannerContainerView (\(loggingAlias))" log.componentName = "NativeBannerContainerView (\(loggingAlias))"
} }
else { else {
log.componentName = "BRNativeBannerContainerView" log.componentName = "NativeBannerContainerView"
} }
} }
} }
private extension BRNativeBannerContainerView { private extension NativeBannerContainerView {
func addAsSubview(view: UIView) { func addAsSubview(view: UIView) {
for subview in subviews { for subview in subviews {
subview.removeFromSuperview() subview.removeFromSuperview()
...@@ -74,20 +76,15 @@ private extension BRNativeBannerContainerView { ...@@ -74,20 +76,15 @@ private extension BRNativeBannerContainerView {
} }
} }
extension BRNativeBannerContainerView: NativeAdLoaderDelegate { extension NativeBannerContainerView: NativeAdLoaderDelegate {
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) { func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADNativeAd) {
log.debug("Banner ad recieved (native_banner) by: \(String(describing: nativeAd.responseInfo.adNetworkClassName))") log.debug("Banner ad recieved (native_banner) by: \(String(describing: nativeAd.responseInfo.adNetworkClassName))")
guard let adView = NativeAdView.instantiateWithXib(adType: adType) else { return }
guard let nativeBannerView = BRNativeBannerView.instantiateWithXib() else { return }
let nativeAdItem = NativeAdItem(nativeAd: nativeAd, adUnitId: adLoader.adUnitID) let nativeAdItem = NativeAdItem(nativeAd: nativeAd, adUnitId: adLoader.adUnitID)
adView.nativeAdItem = nativeAdItem
nativeBannerView.nativeAdItem = nativeAdItem addAsSubview(view: adView)
addAsSubview(view: nativeBannerView)
print("native ad loader: \(String(describing: nativeAd.headline))") print("native ad loader: \(String(describing: nativeAd.headline))")
delegate?.adLoader(adLoader, didReceive: nativeAd) delegate?.adLoader(adLoader, didReceive: nativeAd)
} }
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) { func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: Error) {
...@@ -103,7 +100,7 @@ extension BRNativeBannerContainerView: NativeAdLoaderDelegate { ...@@ -103,7 +100,7 @@ extension BRNativeBannerContainerView: NativeAdLoaderDelegate {
} }
} }
extension BRNativeBannerContainerView: GADBannerViewDelegate { extension NativeBannerContainerView: GADBannerViewDelegate {
func bannerViewDidRecordImpression(_ bannerView: GADBannerView) { func bannerViewDidRecordImpression(_ bannerView: GADBannerView) {
log.info("Impression") log.info("Impression")
......
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="StoriesNativeAd" customModule="BaconReader" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="150"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" placeholderIntrinsicWidth="63.5" placeholderIntrinsicHeight="12" translatesAutoresizingMaskIntoConstraints="NO" id="zEH-Ql-gw6">
<rect key="frame" x="84" y="19" width="63.5" height="16"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sponsored" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qjm-wT-8Rw">
<rect key="frame" x="4" y="2" width="55.5" height="12"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="10"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.086274509799999996" green="0.3411764706" blue="0.64705882349999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="qjm-wT-8Rw" secondAttribute="bottom" constant="2" id="8J5-eu-oQC"/>
<constraint firstAttribute="trailing" secondItem="qjm-wT-8Rw" secondAttribute="trailing" constant="4" id="MGv-iy-QfZ"/>
<constraint firstItem="qjm-wT-8Rw" firstAttribute="leading" secondItem="zEH-Ql-gw6" secondAttribute="leading" constant="4" id="R8t-Nm-VLv"/>
<constraint firstItem="qjm-wT-8Rw" firstAttribute="top" secondItem="zEH-Ql-gw6" secondAttribute="top" constant="2" id="hGu-0V-roG"/>
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Zcd-lU-WbJ" userLabel="adIcon">
<rect key="frame" x="16" y="23" width="60" height="60"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="6fb-gB-UIe"/>
<constraint firstAttribute="height" constant="60" id="Qki-Mq-XKl"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GT6-a9-vaj">
<rect key="frame" x="16" y="0.0" width="304" height="7"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="7" id="hue-AI-6ZU"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="CTA" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="co7-Ei-ydh">
<rect key="frame" x="283.5" y="124" width="28.5" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hHT-Lc-Rw7">
<rect key="frame" x="84" y="43" width="218" height="21"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.84999999999999998" translatesAutoresizingMaskIntoConstraints="NO" id="DaE-WI-yfD">
<rect key="frame" x="84" y="68" width="220" height="48"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="hHT-Lc-Rw7" firstAttribute="top" secondItem="zEH-Ql-gw6" secondAttribute="bottom" constant="8" id="0HK-ag-uVt"/>
<constraint firstAttribute="trailing" secondItem="GT6-a9-vaj" secondAttribute="trailing" id="1Jl-s5-Tuq"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="co7-Ei-ydh" secondAttribute="trailing" constant="8" id="1ws-V8-AaR"/>
<constraint firstItem="zEH-Ql-gw6" firstAttribute="top" secondItem="GT6-a9-vaj" secondAttribute="bottom" constant="12" id="4C6-m3-qEf"/>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="top" secondItem="GT6-a9-vaj" secondAttribute="bottom" constant="16" id="5QM-N6-yc5"/>
<constraint firstAttribute="bottom" secondItem="co7-Ei-ydh" secondAttribute="bottom" constant="8" id="DOI-Rj-exh"/>
<constraint firstItem="DaE-WI-yfD" firstAttribute="top" secondItem="hHT-Lc-Rw7" secondAttribute="bottom" constant="4" id="GDt-xK-IA5"/>
<constraint firstItem="DaE-WI-yfD" firstAttribute="leading" secondItem="Zcd-lU-WbJ" secondAttribute="trailing" constant="8" id="KRk-vx-o7l"/>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="16" id="PX5-9R-fah"/>
<constraint firstItem="co7-Ei-ydh" firstAttribute="top" secondItem="DaE-WI-yfD" secondAttribute="bottom" constant="8" id="Wnj-j7-U0z"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="DaE-WI-yfD" secondAttribute="trailing" constant="16" id="cwe-Xf-rsT"/>
<constraint firstItem="GT6-a9-vaj" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="doH-wQ-96y"/>
<constraint firstItem="zEH-Ql-gw6" firstAttribute="leading" secondItem="Zcd-lU-WbJ" secondAttribute="trailing" constant="8" id="hOk-9R-1no"/>
<constraint firstItem="hHT-Lc-Rw7" firstAttribute="leading" secondItem="Zcd-lU-WbJ" secondAttribute="trailing" constant="8" id="mgD-4F-AiD"/>
<constraint firstItem="GT6-a9-vaj" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="wPd-kl-A9Q"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="hHT-Lc-Rw7" secondAttribute="trailing" constant="18" id="zWY-aK-vI9"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<connections>
<outlet property="bodyView" destination="DaE-WI-yfD" id="a1T-Rh-e3t"/>
<outlet property="callToActionView" destination="co7-Ei-ydh" id="jUA-na-obs"/>
<outlet property="headlineView" destination="hHT-Lc-Rw7" id="sVq-Tb-0Ts"/>
<outlet property="iconView" destination="Zcd-lU-WbJ" id="N8t-b9-lyZ"/>
<outlet property="separator" destination="GT6-a9-vaj" id="6fa-yz-bAC"/>
<outlet property="sponsoredLabel" destination="qjm-wT-8Rw" id="M2U-dH-CQm"/>
<outlet property="sponsoredLabelContainerView" destination="zEH-Ql-gw6" id="Yj1-T1-Wvp"/>
</connections>
<point key="canvasLocation" x="118.84057971014494" y="81.696428571428569"/>
</view>
</objects>
</document>
//
// NativeAd.swift
// BaconReader
//
// Created by Sharad D on 16/09/19.
// Copyright © 2019 OneLouder Apps. All rights reserved.
//
import Foundation
import GoogleMobileAds
//
//class StoriesNativeAd : GADNativeAdView {
// static let AD_SIZE = CGSize(width: 320.0, height: 135.0)
//
// @IBOutlet weak var sponsoredLabel: UILabel!
// @IBOutlet weak var separator: UIView!
// @IBOutlet weak var sponsoredLabelContainerView: UIView!
//
// override var nativeAd: GADNativeAd? {
// didSet {
// setupNativeAdView()
// }
// }
//
// class func nibForAd() -> UINib! {
//
// //TODO: Temporary, update constraints instead of creating new file
// if UserDefaults.standard.bool(for: Setting.leftHandMode) {
// return UINib(nibName: "StoriesLeftNativeAd", bundle: nil)
// } else {
// return UINib(nibName: "StoriesNativeAd", bundle: nil)
// }
// }
//
// override func awakeFromNib() {
// super.awakeFromNib()
//
// sponsoredLabelContainerView.layer.cornerRadius = 4
//
// NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: NSNotification.Name(rawValue: kNotificationThemeChanged), object: nil)
//
// }
//
//
// static let desiredAssets : NSSet =
// NSSet(arrayLiteral: kAdIconImageKey, kAdTitleKey, kAdTextKey, kAdCTATextKey)
//
// override func willMove(toSuperview newSuperview: UIView?) {
// super.willMove(toSuperview: newSuperview)
// updateUI()
// }
//
// fileprivate func cellBackgorundColor() -> UIColor {
// var bgColor: UIColor
//
// let theme = BRThemeType(rawValue: Settings.shared.theme)!
// switch theme {
// case .dark:
// bgColor = UIColor(red: 17, green: 17, blue: 17)
// default:
// bgColor = UIColor(red: 247, green: 247, blue: 247)
// }
//
// return bgColor
// }
//
// private func setupNativeAdView() {
// (bodyView as? UILabel)?.text = nativeAd?.body
// (headlineView as? UILabel)?.text = nativeAd?.headline
// (iconView as? UIImageView)?.image = nativeAd?.icon?.image
// (callToActionView as? UILabel)?.text = nativeAd?.callToAction
// }
//
// @objc private func updateUI() {
//
// let sharedTheme = BRThemeManager.sharedTheme
//
// let isCompact = UserDefaults.standard.bool(for: Setting.compactMode) ;
// if isCompact {
// self.separator.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
// }
// self.separator.backgroundColor = isCompact ? sharedTheme.tableViewSeparatorColor() : sharedTheme.commentSeparatorColor()
//
//
// self.backgroundColor = cellBackgorundColor()
//
// (headlineView as? UILabel)?.textColor = sharedTheme.primaryTextColor()
// (bodyView as? UILabel)?.textColor = sharedTheme.secondaryTextColor()
//
// sponsoredLabel.font = BRThemeManager.sharedTheme.storiesSubredditFont()
//
// (callToActionView as? UILabel)?.textColor = sharedTheme.secondaryTextColor()
//
// #if DEBUG
// if UserDefaults.standard.bool(for: Setting.enableAdLogging) {
// self.debugBorder(UIColor.green)
// }
// #endif
// }
//}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="StoriesNativeAd" customModule="BaconReader" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="150"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GT6-a9-vaj">
<rect key="frame" x="16" y="0.0" width="304" height="0.0"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" id="hue-AI-6ZU"/>
</constraints>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" placeholderIntrinsicWidth="55.5" placeholderIntrinsicHeight="12" translatesAutoresizingMaskIntoConstraints="NO" id="Ghv-7E-DWK">
<rect key="frame" x="16" y="12" width="63.5" height="16"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sponsored" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qjm-wT-8Rw">
<rect key="frame" x="4" y="2" width="55.5" height="12"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="10"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.086274509799999996" green="0.3411764706" blue="0.64705882349999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="qjm-wT-8Rw" secondAttribute="trailing" constant="4" id="OQs-ee-qDe"/>
<constraint firstAttribute="bottom" secondItem="qjm-wT-8Rw" secondAttribute="bottom" constant="2" id="cUz-HN-lqe"/>
<constraint firstItem="qjm-wT-8Rw" firstAttribute="top" secondItem="Ghv-7E-DWK" secondAttribute="top" constant="2" id="g4k-tu-2Pb"/>
<constraint firstItem="qjm-wT-8Rw" firstAttribute="leading" secondItem="Ghv-7E-DWK" secondAttribute="leading" constant="4" id="gW0-Mi-Dev"/>
</constraints>
</view>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Zcd-lU-WbJ" userLabel="adIcon">
<rect key="frame" x="244" y="16" width="60" height="60"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="6fb-gB-UIe"/>
<constraint firstAttribute="height" constant="60" id="Qki-Mq-XKl"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="251" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="749" text="Desc" lineBreakMode="tailTruncation" numberOfLines="5" baselineAdjustment="alignBaselines" minimumFontSize="7" adjustsFontForContentSizeCategory="YES" translatesAutoresizingMaskIntoConstraints="NO" id="U8B-WH-Pg0">
<rect key="frame" x="16" y="67" width="212" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="9" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wBR-ft-sY5" userLabel="titleLabel">
<rect key="frame" x="16" y="42.5" width="212" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="center" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sJF-OY-AlZ">
<rect key="frame" x="304" y="134" width="0.0" height="0.0"/>
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="15"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="leading" secondItem="wBR-ft-sY5" secondAttribute="trailing" constant="16" id="0e8-9z-2vV"/>
<constraint firstItem="U8B-WH-Pg0" firstAttribute="top" secondItem="wBR-ft-sY5" secondAttribute="bottom" constant="4" id="2wA-y3-Q44"/>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="top" secondItem="GT6-a9-vaj" secondAttribute="bottom" constant="16" id="5QM-N6-yc5"/>
<constraint firstItem="U8B-WH-Pg0" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="16" id="6VA-cN-0b6"/>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="leading" secondItem="U8B-WH-Pg0" secondAttribute="trailing" constant="16" id="93B-vj-Gs5"/>
<constraint firstItem="sJF-OY-AlZ" firstAttribute="top" relation="greaterThanOrEqual" secondItem="Zcd-lU-WbJ" secondAttribute="bottom" constant="8" id="D2c-Z1-yTJ"/>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="iN0-l3-epB" secondAttribute="trailing" constant="-76" id="Ea7-XE-D0E"/>
<constraint firstItem="Ghv-7E-DWK" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="QUs-cr-nVf"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="sJF-OY-AlZ" secondAttribute="bottom" constant="16" id="Qe1-cX-qyW"/>
<constraint firstItem="Zcd-lU-WbJ" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" constant="-16" id="VqL-pY-cAY"/>
<constraint firstItem="Ghv-7E-DWK" firstAttribute="top" secondItem="GT6-a9-vaj" secondAttribute="bottom" constant="12" id="coU-2X-jKZ"/>
<constraint firstItem="wBR-ft-sY5" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="16" id="eCp-Cy-Lzm"/>
<constraint firstAttribute="trailing" secondItem="GT6-a9-vaj" secondAttribute="trailing" id="eT4-PF-VvJ"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="U8B-WH-Pg0" secondAttribute="bottom" constant="16" id="k3b-zt-hNq"/>
<constraint firstItem="sJF-OY-AlZ" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" constant="-16" id="l61-h4-EAP"/>
<constraint firstItem="GT6-a9-vaj" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="wPd-kl-A9Q"/>
<constraint firstItem="wBR-ft-sY5" firstAttribute="top" secondItem="Ghv-7E-DWK" secondAttribute="bottom" constant="14.5" id="xT3-JR-J3i"/>
<constraint firstItem="GT6-a9-vaj" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="16" id="yEm-Lw-IaJ"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="bodyView" destination="U8B-WH-Pg0" id="c1B-0S-zjE"/>
<outlet property="callToActionView" destination="sJF-OY-AlZ" id="7Hw-Wa-rhY"/>
<outlet property="headlineView" destination="wBR-ft-sY5" id="dTr-tj-H4P"/>
<outlet property="iconView" destination="Zcd-lU-WbJ" id="L5F-j9-iyW"/>
<outlet property="separator" destination="GT6-a9-vaj" id="P08-Jb-Dex"/>
<outlet property="sponsoredLabel" destination="qjm-wT-8Rw" id="xn4-tZ-7mj"/>
<outlet property="sponsoredLabelContainerView" destination="Ghv-7E-DWK" id="05s-mR-tuf"/>
</connections>
<point key="canvasLocation" x="137.68115942028987" y="78.348214285714278"/>
</view>
</objects>
</document>
//
// StoriesNativeAdCell.swift
// BaconReader
//
// Created by Rishab Dutta on 27/07/20.
// Copyright © 2020 OneLouder Apps. All rights reserved.
//
import UIKit
import GoogleMobileAds
//
//class StoriesNativeAdCell: UICollectionViewCell {
//
// private var separatorHeight: CGFloat { return (UserDefaults.standard.bool(for: Setting.compactMode)) ? 1.0 : 7.0 }
//
//
// private lazy var separatorView: UIView = {
// let sv = UIView()
// sv.translatesAutoresizingMaskIntoConstraints = false
// sv.backgroundColor = (UserDefaults.standard.bool(for: Setting.compactMode)) ? BRThemeManager.sharedTheme.tableViewSeparatorColor() : BRThemeManager.sharedTheme.commentSeparatorColor()
//
// return sv
// }()
//
// private var separatorViewHeightConstraint: NSLayoutConstraint!
//
// var nativeAdView: StoriesNativeAd?
//
// var bannerAdContainerView: UIView = {
// let bView = UIView()
// bView.translatesAutoresizingMaskIntoConstraints = false
// bView.clipsToBounds = false
// return bView
// }()
//
// var nativeAdItem: NativeAdItem? {
// didSet {
//
// guard let adItem = nativeAdItem else { return }
// switch adItem.adType {
// case .native:
// nativeAdView?.nativeAd = nativeAdItem?.nativeAd
// nativeAdView?.isHidden = false
// bannerAdContainerView.isHidden = true
// case .banner:
// let bannerView = nativeAdItem?.bannerAd ?? GAMBannerView()
// addToContainer(bannerView)
// bannerView.clipsToBounds = false
// addShadow(bannerAd: bannerView)
//
// bannerAdContainerView.isHidden = false
// nativeAdView?.isHidden = true
// }
// }
// }
//
// override func awakeFromNib() {
// super.awakeFromNib()
// contentView.addSubview(separatorView)
// contentView.addSubview(bannerAdContainerView)
//
// addNativeAdToSubview()
// addBannerToSubview()
//
// NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: NSNotification.Name(rawValue: kNotificationThemeChanged), object: nil)
// }
//
//
//
// private func addBannerToSubview() {
// separatorViewHeightConstraint = separatorView.heightAnchor.constraint(equalToConstant: separatorHeight)
// NSLayoutConstraint.activate([
// separatorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16.0),
// separatorView.topAnchor.constraint(equalTo: contentView.topAnchor),
// separatorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
// separatorViewHeightConstraint,
//
// bannerAdContainerView.widthAnchor.constraint(equalToConstant: 320),
// bannerAdContainerView.heightAnchor.constraint(equalToConstant: 50),
// bannerAdContainerView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
// bannerAdContainerView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
// ])
// }
//
// private func addToContainer(_ bannerView: GAMBannerView) {
// bannerAdContainerView.subviews.forEach { (subview) in
// subview.removeFromSuperview()
// }
//
// bannerAdContainerView.addSubview(bannerView)
// bannerView.translatesAutoresizingMaskIntoConstraints = false
//
// NSLayoutConstraint.activate([
// bannerView.topAnchor.constraint(equalTo: bannerAdContainerView.topAnchor),
// bannerView.leadingAnchor.constraint(equalTo: bannerAdContainerView.leadingAnchor),
// bannerView.bottomAnchor.constraint(equalTo: bannerAdContainerView.bottomAnchor),
// bannerView.trailingAnchor.constraint(equalTo: bannerAdContainerView.trailingAnchor),
// ])
// }
//
// func addNativeAdToSubview() {
// nativeAdView?.subviews.forEach({ (subview) in
// subview.removeFromSuperview()
// })
//
// nativeAdView = StoriesNativeAd.nibForAd()?.instantiate(withOwner: self, options: nil).first as? StoriesNativeAd
// if let nav = nativeAdView {
// nav.translatesAutoresizingMaskIntoConstraints = false
// contentView.addSubview(nav)
// NSLayoutConstraint.activate([
// nav.topAnchor.constraint(equalTo: separatorView.bottomAnchor),
// nav.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
// nav.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
// nav.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
// ])
// }
// }
//
// private func addShadow(bannerAd: GAMBannerView) {
// let theme = BRThemeType(rawValue: Settings.shared.theme)!
//
// var shadowColor: UIColor = UIColor()
// switch theme {
// case .default:
// shadowColor = .black
// case .dark:
// shadowColor = .white
// case .light:
// shadowColor = .black
// }
// bannerAd.addShadow(with: shadowColor, alpha: 0.5, radius: 5, offset: .zero)
// }
//
// @objc private func updateUI() {
// let isCompact = UserDefaults.standard.bool(for: Setting.compactMode) ;
//
// if isCompact {
// separatorViewHeightConstraint.constant = 1
// }
//
// separatorView.backgroundColor = isCompact ? BRThemeManager.sharedTheme.tableViewSeparatorColor() : BRThemeManager.sharedTheme.commentSeparatorColor()
//
// if let bannerView = bannerAdContainerView.subviews.first as? GAMBannerView {
// addShadow(bannerAd: bannerView)
// }
// }
//}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="collection view cell content view" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="StoriesNativeAdCell" id="wT6-Hq-asB" customClass="StoriesNativeAdCell" customModule="BaconReader" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="go0-GN-nZN">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
</collectionViewCellContentView>
<point key="canvasLocation" x="58" y="-129"/>
</collectionViewCell>
</objects>
</document>
...@@ -7,7 +7,19 @@ ...@@ -7,7 +7,19 @@
import UIKit import UIKit
extension CellFactoryProtocol { public protocol CellFactory {
var numberOfSections:Int { get }
func numberOfRows(inSection section:Int) -> Int
func registerCells(on tableView:UITableView)
func cellFromTableView(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell
}
public protocol CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory)
}
// MARK: - Default methods implementation
extension CellFactory {
func dequeueReusableCell<T: ReusableCellProtocol>(type:T.Type, tableView:UITableView, indexPath: IndexPath) -> T { func dequeueReusableCell<T: ReusableCellProtocol>(type:T.Type, tableView:UITableView, indexPath: IndexPath) -> T {
let cell = tableView.dequeueReusableCell(withIdentifier: T.kIdentifier, for: indexPath) as! T let cell = tableView.dequeueReusableCell(withIdentifier: T.kIdentifier, for: indexPath) as! T
return cell return cell
...@@ -17,10 +29,3 @@ extension CellFactoryProtocol { ...@@ -17,10 +29,3 @@ extension CellFactoryProtocol {
tableView.register(type, forCellReuseIdentifier: T.kIdentifier) tableView.register(type, forCellReuseIdentifier: T.kIdentifier)
} }
} }
public protocol CellFactoryProtocol {
var numberOfSections:Int { get }
func numberOfRows(inSection section:Int) -> Int
func registerCells(on tableView:UITableView)
func cellFromTableView(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell
}
...@@ -393,6 +393,9 @@ ...@@ -393,6 +393,9 @@
<key>UIAppFonts</key> <key>UIAppFonts</key>
<array> <array>
<string>SF-Pro.ttf</string> <string>SF-Pro.ttf</string>
<string>SF-Compact-Display-Light.otf</string>
<string>SF-Compact-Display-Regular.otf</string>
<string>SF-Compact-Display-Semibold.otf</string>
</array> </array>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
......
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "group4Copy2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.286",
"green" : "0.434",
"red" : "0.182"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.286",
"green" : "0.434",
"red" : "0.182"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
...@@ -268,3 +268,7 @@ ...@@ -268,3 +268,7 @@
// Humidity type, for smart texts // Humidity type, for smart texts
"humidity.type.high" = "high"; "humidity.type.high" = "high";
"humidity.type.low" = "low"; "humidity.type.low" = "low";
// Ads
"ads.native.sponsored" = "Sponsored";
"ads.placeholder" = "Advertisment";
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
import UIKit import UIKit
public struct AppFont { public struct AppFont {
private static func fontDescriptor(size:CGFloat, weight:UIFont.Weight) -> UIFontDescriptor { private static func fontDescriptor(family: String, size:CGFloat, weight:UIFont.Weight) -> UIFontDescriptor {
let traitsDict = [UIFontDescriptor.TraitKey.weight: weight] let traitsDict = [UIFontDescriptor.TraitKey.weight: weight]
let descriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptor.AttributeName.size : size, let descriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptor.AttributeName.size : size,
UIFontDescriptor.AttributeName.family : "SF Pro", UIFontDescriptor.AttributeName.family : family,
UIFontDescriptor.AttributeName.traits : traitsDict UIFontDescriptor.AttributeName.traits : traitsDict
]) ])
...@@ -25,7 +25,7 @@ public struct AppFont { ...@@ -25,7 +25,7 @@ public struct AppFont {
if let cached = fontCache[weigth]?[size] { if let cached = fontCache[weigth]?[size] {
return cached return cached
} }
let descriptor = AppFont.fontDescriptor(size: size, weight: weigth) let descriptor = AppFont.fontDescriptor(family: "SF Pro", size: size, weight: weigth)
let font = UIFont(descriptor: descriptor, size: size) let font = UIFont(descriptor: descriptor, size: size)
if fontCache[weigth] == nil { if fontCache[weigth] == nil {
fontCache[weigth] = [size: font] fontCache[weigth] = [size: font]
...@@ -52,4 +52,35 @@ public struct AppFont { ...@@ -52,4 +52,35 @@ public struct AppFont {
font(weigth: .semibold, size: size) font(weigth: .semibold, size: size)
} }
} }
public struct SFCompactDisplay {
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 = AppFont.fontDescriptor(family: "SF Compact 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)
}
static func semibold(size: CGFloat) -> UIFont {
font(weigth: .semibold, size: size)
}
}
} }
...@@ -165,7 +165,6 @@ class ForecastTimePeriodView: UIView { ...@@ -165,7 +165,6 @@ class ForecastTimePeriodView: UIView {
} }
private func updateGraphLayout() { private func updateGraphLayout() {
print("[ForecastTimePeriod] Update graph layout")
graphRect = (stackView.arrangedSubviews.first as? PeriodButtonProtocol)?.graphRect ?? .zero graphRect = (stackView.arrangedSubviews.first as? PeriodButtonProtocol)?.graphRect ?? .zero
graphView.frame = .init(x: 0, graphView.frame = .init(x: 0,
y: graphRect.origin.y, y: graphRect.origin.y,
...@@ -299,8 +298,6 @@ class ForecastTimePeriodView: UIView { ...@@ -299,8 +298,6 @@ class ForecastTimePeriodView: UIView {
self.graphView.drawAdditionalGraph(with: [CGPoint]()) self.graphView.drawAdditionalGraph(with: [CGPoint]())
self.tintGraphAt(button: selectedButton) self.tintGraphAt(button: selectedButton)
} }
print("[ForecastTimePeriod] Draw graph")
} }
private func tintGraphAt(button:PeriodButtonProtocol) { private func tintGraphAt(button:PeriodButtonProtocol) {
......
...@@ -115,4 +115,9 @@ struct DefaultTheme: ThemeProtocol { ...@@ -115,4 +115,9 @@ struct DefaultTheme: ThemeProtocol {
var mapControlsColor: UIColor { var mapControlsColor: UIColor {
return UIColor(named: "map_controls_color") ?? .red return UIColor(named: "map_controls_color") ?? .red
} }
//Ads
var nativeAdCallToActionColor: UIColor {
return UIColor(named: "native_ad_call_to_action_background") ?? .red
}
} }
...@@ -49,4 +49,7 @@ public protocol ThemeProtocol { ...@@ -49,4 +49,7 @@ public protocol ThemeProtocol {
//Map //Map
var mapControlsColor:UIColor { get } var mapControlsColor:UIColor { get }
//Ads
var nativeAdCallToActionColor: UIColor { get }
} }
//
// TodayAdCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 12.02.2021.
//
import UIKit
protocol AdCell {
var adView: AdView? { get set }
}
// //
// TodayAdCell.swift // BannerAdCell.swift
// 1Weather // 1Weather
// //
// Created by Dmitry Stepanets on 12.02.2021. // Created by Dmitry Stepanets on 12.02.2021.
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
import UIKit import UIKit
class AdCell: UITableViewCell { class BannerAdCell: UITableViewCell, AdCell {
//Private //Private
private let container = UIView() private let container = UIView()
private let label = UILabel() private let label = UILabel()
...@@ -60,13 +61,15 @@ class AdCell: UITableViewCell { ...@@ -60,13 +61,15 @@ class AdCell: UITableViewCell {
} }
//MARK:- Prepare //MARK:- Prepare
private extension AdCell { private extension BannerAdCell {
func prepareCellStyle() { func prepareCellStyle() {
selectionStyle = .none selectionStyle = .none
clipsToBounds = true
} }
func prepareContainer() { func prepareContainer() {
container.layer.cornerRadius = 6 container.layer.cornerRadius = 6
container.clipsToBounds = true
contentView.addSubview(container) contentView.addSubview(container)
container.snp.makeConstraints { (make) in container.snp.makeConstraints { (make) in
...@@ -82,7 +85,7 @@ private extension AdCell { ...@@ -82,7 +85,7 @@ private extension AdCell {
subview.removeFromSuperview() subview.removeFromSuperview()
} }
label.text = "Advertisment" label.text = "ads.placeholder".localized()
label.font = AppFont.SFPro.regular(size: 14) label.font = AppFont.SFPro.regular(size: 14)
container.addSubview(label) container.addSubview(label)
......
//
// MRECAdCell.swift
// 1Weather
//
// Created by Demid Merzlyakov on 08.06.2021.
//
import UIKit
class MRECAdCell: UITableViewCell, AdCell {
//Private
private let container = UIView()
private let label = UILabel()
public var adView: AdView? = nil {
didSet {
guard adView != oldValue else {
return
}
prepareAd()
}
}
private let gradientView = GradientView(startColor: UIColor.white.withAlphaComponent(0),
endColor: UIColor(hex: 0xdaddec),
opacity: 0.5)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
prepareCell()
prepareContainer()
prepareAd()
prepareGradient()
updateUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
updateUI()
}
private func updateUI() {
contentView.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
container.backgroundColor = ThemeManager.currentTheme.containerBackgroundColor
label.textColor = ThemeManager.currentTheme.secondaryTextColor
switch interfaceStyle {
case .light:
gradientView.isHidden = false
case .dark:
gradientView.isHidden = true
}
}
}
//MARK:- Prepare
private extension MRECAdCell {
func prepareCell() {
selectionStyle = .none
clipsToBounds = true
}
func prepareContainer() {
label.text = "ads.placeholder".localized()
label.font = AppFont.SFPro.regular(size: 10)
label.textColor = ThemeManager.currentTheme.secondaryTextColor
contentView.addSubview(label)
contentView.addSubview(container)
label.snp.makeConstraints { make in
make.top.equalToSuperview().inset(18)
make.trailing.equalTo(container.snp.trailing)
}
container.snp.makeConstraints { (make) in
make.top.equalTo(label.snp.bottom).offset(6)
make.height.equalTo(250)
make.bottom.equalToSuperview().inset(18)
make.centerX.equalToSuperview()
make.width.greaterThanOrEqualTo(300)
}
}
func prepareAd() {
for subview in container.subviews {
subview.removeFromSuperview()
}
if let adView = adView {
container.addSubview(adView)
adView.snp.makeConstraints { (make) in
make.center.equalToSuperview()
make.size.equalToSuperview()
}
}
}
func prepareGradient() {
contentView.addSubview(gradientView)
contentView.bringSubviewToFront(container)
gradientView.snp.makeConstraints { (make) in
make.left.bottom.right.equalToSuperview()
make.height.equalToSuperview().multipliedBy(0.5)
}
}
}
...@@ -6,48 +6,68 @@ ...@@ -6,48 +6,68 @@
// //
import UIKit import UIKit
import OneWeatherCore
private enum DailyForecastCellType:Int, CaseIterable { private enum ForecastCellType {
case forecast = 0 //Daily
case forecastInfo case forecastDaily
// case forecast case forecastDailyInfo
// case conditions
// case precipitation
// case dayTime
case sun case sun
case moon case moon
}
private enum HourlyForecastCellType: Int, CaseIterable { // Hourly
case day case day
case forecastHourly case forecastHourly
case precipitation case precipitation
case wind case wind
// Shared
case adBanner
case adMREC
} }
private struct CellsToUpdate:OptionSet { private struct HourlySection {
let rawValue: Int let rows: [ForecastCellType] = {
let showAds = !isAppPro() && AdConfigManager.shared.adConfig.adsEnabled
if showAds {
return [.day, .forecastHourly, .adBanner, .precipitation, .wind, .adMREC]
}
else {
return [.day, .forecastHourly, .precipitation, .wind]
}
}()
}
static let dailyTimePeriod = CellsToUpdate(rawValue: 1 << 0) private struct DailySection {
static let hourlyTimePeriod = CellsToUpdate(rawValue: 1 << 1) let rows: [ForecastCellType] = {
static let dailyForecastInfoCell = CellsToUpdate(rawValue: 1 << 2) let showAds = !isAppPro() && AdConfigManager.shared.adConfig.adsEnabled
static let precipitation = CellsToUpdate(rawValue: 1 << 4) if showAds {
static let wind = CellsToUpdate(rawValue: 1 << 5) return [.forecastDaily, .forecastDailyInfo, .adBanner, .sun, .moon, .adMREC]
}
else {
return [.forecastDaily, .forecastDailyInfo, .sun, .moon]
}
}()
} }
class ForecastCellFactory: CellFactoryProtocol {
class ForecastCellFactory: CellFactory {
//Private //Private
private var cellsToUpdate:CellsToUpdate = [.dailyTimePeriod, .hourlyTimePeriod, .dailyForecastInfoCell, .precipitation, .wind] private let dailySection = DailySection()
private let hourlySection = HourlySection()
private var cellsToUpdate: Set<ForecastCellType> = [.forecastDaily, .forecastHourly, .forecastDailyInfo, .precipitation, .wind]
private let forecastViewModel:ForecastViewModel private let forecastViewModel:ForecastViewModel
public var timePeriod = TimePeriod.daily private var adViewCache = [TimePeriod: [IndexPath: AdView]]()
//Public //Public
var numberOfSections: Int { public var delegate: CellFactoryDelegate?
public var timePeriod = TimePeriod.daily
public var numberOfSections: Int {
return 1 return 1
} }
public func numberOfRows(inSection section: Int) -> Int { public func numberOfRows(inSection section: Int) -> Int {
return timePeriod == .daily ? DailyForecastCellType.allCases.count : HourlyForecastCellType.allCases.count return timePeriod == .daily ? dailySection.rows.count : hourlySection.rows.count
} }
public init(viewModel: ForecastViewModel) { public init(viewModel: ForecastViewModel) {
...@@ -63,44 +83,14 @@ class ForecastCellFactory: CellFactoryProtocol { ...@@ -63,44 +83,14 @@ class ForecastCellFactory: CellFactoryProtocol {
registerCell(type: ForecastWindSpeedCell.self, tableView: tableView) registerCell(type: ForecastWindSpeedCell.self, tableView: tableView)
registerCell(type: SunPhaseCell.self, tableView: tableView) registerCell(type: SunPhaseCell.self, tableView: tableView)
registerCell(type: MoonPhaseCell.self, tableView: tableView) registerCell(type: MoonPhaseCell.self, tableView: tableView)
registerCell(type: BannerAdCell.self, tableView: tableView)
registerCell(type: MRECAdCell.self, tableView: tableView)
} }
public func cellFromTableView(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell { public func cellFromTableView(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell {
switch timePeriod { let cellType = cellType(at: indexPath)
case .daily:
return dailyCellFor(tableView: tableView, indexPath: indexPath)
case .hourly:
return hourlyCellFor(tableView: tableView, indexPath: indexPath)
}
}
public func setNeedsUpdate() {
self.cellsToUpdate = [.dailyTimePeriod, .hourlyTimePeriod, .dailyForecastInfoCell, .precipitation, .wind]
}
public func selectedWeatherDidChange() {
self.cellsToUpdate = [.dailyForecastInfoCell, .precipitation, .wind]
}
public func willDisplay(cell:UITableViewCell) {
switch cell {
case let sunCell as SunPhaseCell:
sunCell.updateSunPosition()
case let moonCell as MoonPhaseCell:
moonCell.updateMoonPosition()
default:
break
}
}
//Private
private func dailyCellFor(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell {
guard let cellType = DailyForecastCellType(rawValue: indexPath.row) else {
return UITableViewCell()
}
switch cellType { switch cellType {
case .forecast: case .forecastDaily:
let cell = dequeueReusableCell(type: ForecastDailyCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: ForecastDailyCell.self, tableView: tableView, indexPath: indexPath)
cell.delegate = self cell.delegate = self
...@@ -108,19 +98,19 @@ class ForecastCellFactory: CellFactoryProtocol { ...@@ -108,19 +98,19 @@ class ForecastCellFactory: CellFactoryProtocol {
cell.setOffset(offset: forecastViewModel.offsetHolder.currentOffset, cell.setOffset(offset: forecastViewModel.offsetHolder.currentOffset,
selectedButton: forecastViewModel.selectedDailyWeatherIndex) selectedButton: forecastViewModel.selectedDailyWeatherIndex)
if cellsToUpdate.contains(.dailyTimePeriod) { if cellsToUpdate.contains(.forecastDaily) {
cell.configure(daily: daily) cell.configure(daily: daily)
cellsToUpdate.remove(.dailyTimePeriod) cellsToUpdate.remove(.forecastDaily)
} }
} }
return cell return cell
case .forecastInfo: case .forecastDailyInfo:
let cell = dequeueReusableCell(type: ForecastInfoCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: ForecastInfoCell.self, tableView: tableView, indexPath: indexPath)
if let daily = forecastViewModel.selectedDailyWeather { if let daily = forecastViewModel.selectedDailyWeather {
if cellsToUpdate.contains(.dailyForecastInfoCell) { if cellsToUpdate.contains(.forecastDailyInfo) {
cell.configure(dailyWeather: daily) cell.configure(dailyWeather: daily)
cellsToUpdate.remove(.dailyForecastInfoCell) cellsToUpdate.remove(.forecastDailyInfo)
} }
} }
...@@ -137,15 +127,14 @@ class ForecastCellFactory: CellFactoryProtocol { ...@@ -137,15 +127,14 @@ class ForecastCellFactory: CellFactoryProtocol {
cell.configure(with: loc) cell.configure(with: loc)
} }
return cell return cell
} case .adBanner:
} let cell = dequeueReusableCell(type: BannerAdCell.self, tableView: tableView, indexPath: indexPath)
cell.adView = adView(for: timePeriod, indexPath: indexPath)
private func hourlyCellFor(tableView:UITableView, indexPath:IndexPath) -> UITableViewCell { return cell
guard let cellType = HourlyForecastCellType(rawValue: indexPath.row) else { case .adMREC:
return UITableViewCell() let cell = dequeueReusableCell(type: MRECAdCell.self, tableView: tableView, indexPath: indexPath)
} cell.adView = adView(for: timePeriod, indexPath: indexPath)
return cell
switch cellType {
case .day: case .day:
let cell = dequeueReusableCell(type: ForecastDayCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: ForecastDayCell.self, tableView: tableView, indexPath: indexPath)
if let today = forecastViewModel.location?.today{ if let today = forecastViewModel.location?.today{
...@@ -155,9 +144,9 @@ class ForecastCellFactory: CellFactoryProtocol { ...@@ -155,9 +144,9 @@ class ForecastCellFactory: CellFactoryProtocol {
case .forecastHourly: case .forecastHourly:
let cell = dequeueReusableCell(type: ForecastHourlyCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: ForecastHourlyCell.self, tableView: tableView, indexPath: indexPath)
if let hourly = forecastViewModel.location?.hourly { if let hourly = forecastViewModel.location?.hourly {
if cellsToUpdate.contains(.hourlyTimePeriod) { if cellsToUpdate.contains(.forecastHourly) {
cell.configure(hourly: hourly) cell.configure(hourly: hourly)
cellsToUpdate.remove(.hourlyTimePeriod) cellsToUpdate.remove(.forecastHourly)
} }
} }
return cell return cell
...@@ -181,6 +170,99 @@ class ForecastCellFactory: CellFactoryProtocol { ...@@ -181,6 +170,99 @@ class ForecastCellFactory: CellFactoryProtocol {
return cell return cell
} }
} }
private func cellType(at indexPath: IndexPath) -> ForecastCellType {
switch timePeriod {
case .daily:
return self.dailySection.rows[indexPath.row]
case .hourly:
return self.hourlySection.rows[indexPath.row]
}
}
public func height(for indexPath: IndexPath) -> CGFloat {
let cellType = cellType(at: indexPath)
switch cellType {
case .adBanner: fallthrough
case .adMREC:
let adView = adView(for: timePeriod, indexPath: indexPath)
return adView.adReady ? UITableView.automaticDimension : 0
default:
return UITableView.automaticDimension
}
}
public func setNeedsUpdate() {
self.cellsToUpdate = [.forecastDaily, .forecastHourly, .forecastDailyInfo, .precipitation, .wind]
}
public func selectedWeatherDidChange() {
self.cellsToUpdate = [.forecastDailyInfo, .precipitation, .wind]
}
public func willDisplay(cell:UITableViewCell) {
switch cell {
case let sunCell as SunPhaseCell:
sunCell.updateSunPosition()
case let moonCell as MoonPhaseCell:
moonCell.updateMoonPosition()
case let adCell as AdCell:
adCell.adView?.start()
default:
break
}
}
public func didHide(cell: UITableViewCell) {
switch cell {
case let adCell as AdCell:
adCell.adView?.stop()
default:
break
}
}
private func adView(for timePeriod: TimePeriod, indexPath: IndexPath) -> AdView {
if let adView = adViewCache[self.timePeriod]?[indexPath] {
return adView
}
let adView = AdView()
adView.delegate = self
var placementName: String!
var timePeriodString: String!
var adType = AdType.banner
var adTypeString = "Banner"
var adLoggingEmoji = "🔹"
switch timePeriod {
case .daily:
timePeriodString = "D"
placementName = placementNameForecastDailyBanner
let cellType = cellType(at: indexPath)
if cellType == .adMREC {
placementName = placementNameForecastDailySquare
adType = .square
adTypeString = "MREC"
adLoggingEmoji = "✅"
}
case .hourly:
placementName = placementNameForecastHourlyBanner
timePeriodString = "H"
let cellType = cellType(at: indexPath)
if cellType == .adMREC {
placementName = placementNameForecastHourlySquare
adType = .square
adTypeString = "MREC"
adLoggingEmoji = "✅"
}
}
adView.set(placementName: placementName, adType: adType)
adView.loggingAlias = "\(adLoggingEmoji) Forecast \(timePeriodString!) \(adTypeString)"
var edited = adViewCache[timePeriod] ?? [IndexPath: AdView]()
edited[indexPath] = adView
adViewCache[timePeriod] = edited
return adView
}
} }
//MARK:- ForecastTimePeriodCell Delegate //MARK:- ForecastTimePeriodCell Delegate
...@@ -193,3 +275,22 @@ extension ForecastCellFactory: ForecastDailyCellDelegate { ...@@ -193,3 +275,22 @@ extension ForecastCellFactory: ForecastDailyCellDelegate {
forecastViewModel.offsetHolder.update(offset: offset) forecastViewModel.offsetHolder.update(offset: offset)
} }
} }
// MARK: - AdViewDelegate
extension ForecastCellFactory: AdViewDelegate {
func succeeded(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
func failed(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
}
...@@ -31,6 +31,7 @@ class ForecastViewController: UIViewController { ...@@ -31,6 +31,7 @@ class ForecastViewController: UIViewController {
self.coordinator = coordinator self.coordinator = coordinator
self.forecastCellFactory = ForecastCellFactory(viewModel: viewModel) self.forecastCellFactory = ForecastCellFactory(viewModel: viewModel)
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
self.forecastCellFactory.delegate = self
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
...@@ -160,7 +161,6 @@ private extension ForecastViewController { ...@@ -160,7 +161,6 @@ private extension ForecastViewController {
tableView.separatorStyle = .none tableView.separatorStyle = .none
tableView.tableFooterView = UIView() tableView.tableFooterView = UIView()
tableView.estimatedRowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.rowHeight = UITableView.automaticDimension
tableView.delegate = self tableView.delegate = self
tableView.dataSource = self tableView.dataSource = self
view.addSubview(tableView) view.addSubview(tableView)
...@@ -248,6 +248,10 @@ extension ForecastViewController: UITableViewDataSource { ...@@ -248,6 +248,10 @@ extension ForecastViewController: UITableViewDataSource {
return forecastCellFactory.cellFromTableView(tableView: tableView, return forecastCellFactory.cellFromTableView(tableView: tableView,
indexPath: indexPath) indexPath: indexPath)
} }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
forecastCellFactory.height(for: indexPath)
}
} }
//MARK:- ViewModel Delegate //MARK:- ViewModel Delegate
...@@ -279,3 +283,9 @@ extension ForecastViewController: DaysControlViewDelegate { ...@@ -279,3 +283,9 @@ extension ForecastViewController: DaysControlViewDelegate {
viewModel.offsetHolder.update(offset: offset) viewModel.offsetHolder.update(offset: offset)
} }
} }
extension ForecastViewController: CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory) {
self.tableView.reloadData()
}
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
import UIKit import UIKit
import OneWeatherCore import OneWeatherCore
class LocationCellFactory: CellFactoryProtocol { class LocationCellFactory: CellFactory {
//Private //Private
private let locationsViewModel:LocationsViewModel private let locationsViewModel:LocationsViewModel
......
...@@ -91,7 +91,7 @@ private struct SectionItem { ...@@ -91,7 +91,7 @@ private struct SectionItem {
let rows:[MenuRow] let rows:[MenuRow]
} }
class MenuCellFactory<T>: CellFactoryProtocol { class MenuCellFactory<T>: CellFactory {
//Private //Private
private let menuViewModel:MenuViewModel private let menuViewModel:MenuViewModel
private let sections:[SectionItem] = [SectionItem(type: .info, rows: [.settings]), private let sections:[SectionItem] = [SectionItem(type: .info, rows: [.settings]),
......
...@@ -12,7 +12,8 @@ fileprivate enum NWSAlertCellType: Int { ...@@ -12,7 +12,8 @@ fileprivate enum NWSAlertCellType: Int {
case header = 0 case header = 0
case forecastOffice case forecastOffice
case extendedInfoBlock case extendedInfoBlock
case ad case adBanner
case adMREC
} }
fileprivate protocol NWSAlertTableViewSection { fileprivate protocol NWSAlertTableViewSection {
...@@ -31,9 +32,17 @@ fileprivate struct HeaderSection: NWSAlertTableViewSection { ...@@ -31,9 +32,17 @@ fileprivate struct HeaderSection: NWSAlertTableViewSection {
//do nothing //do nothing
} }
private let rows: [NWSAlertCellType] = [.header, .forecastOffice] private let rows: [NWSAlertCellType] = {
if !isAppPro() && AdConfigManager.shared.adConfig.adsEnabled {
return [.header, .forecastOffice, .adBanner]
}
else {
return [.header, .forecastOffice]
}
}()
var numberOfRows: Int { var numberOfRows: Int {
return rows.count rows.count
} }
func type(forRow row: Int) -> NWSAlertCellType { func type(forRow row: Int) -> NWSAlertCellType {
...@@ -43,19 +52,13 @@ fileprivate struct HeaderSection: NWSAlertTableViewSection { ...@@ -43,19 +52,13 @@ fileprivate struct HeaderSection: NWSAlertTableViewSection {
fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection { fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection {
private var alert: NWSAlert private var alert: NWSAlert
private var countOfAds: Int {
if !isAppPro() && AdConfigManager.shared.adConfig.adsEnabled {
return 1
}
return 0
}
init(alert: NWSAlert) { init(alert: NWSAlert) {
self.alert = alert self.alert = alert
} }
var numberOfRows: Int { var numberOfRows: Int {
countOfAds + (alert.extendedInfo?.infoBlocks.count ?? 0) alert.extendedInfo?.infoBlocks.count ?? 0
} }
mutating func update(with alert: NWSAlert) { mutating func update(with alert: NWSAlert) {
...@@ -63,29 +66,19 @@ fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection { ...@@ -63,29 +66,19 @@ fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection {
} }
func type(forRow row: Int) -> NWSAlertCellType { func type(forRow row: Int) -> NWSAlertCellType {
guard countOfAds > 0 else { .extendedInfoBlock
return .extendedInfoBlock
}
if numberOfRows == 1 {
return .ad
}
else {
if row == 1 {
return .ad
}
else {
return .extendedInfoBlock
}
}
} }
let rows: [NWSAlertCellType] = [.extendedInfoBlock] let rows: [NWSAlertCellType] = [.extendedInfoBlock]
} }
class NWSAlertCellFactory: CellFactoryProtocol { class NWSAlertCellFactory: CellFactory {
var alert: NWSAlert { fileprivate var sections: [NWSAlertTableViewSection]
private var adViewCache = [IndexPath: AdView]()
public var delegate: CellFactoryDelegate?
public var alert: NWSAlert {
didSet { didSet {
for i in 0..<sections.count { for i in 0..<sections.count {
sections[i].update(with: alert) sections[i].update(with: alert)
...@@ -93,19 +86,28 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -93,19 +86,28 @@ class NWSAlertCellFactory: CellFactoryProtocol {
} }
} }
init(alert: NWSAlert) { public init(alert: NWSAlert) {
self.alert = alert self.alert = alert
self.sections = [HeaderSection(alert: alert), ExtendedInfoSection(alert: alert)] self.sections = [HeaderSection(alert: alert), ExtendedInfoSection(alert: alert)]
} }
fileprivate var sections: [NWSAlertTableViewSection] public func height(for indexPath: IndexPath) -> CGFloat {
private var adViewCache = [IndexPath: AdView]() let cellType = cellType(at: indexPath)
switch cellType {
case .adBanner: fallthrough
case .adMREC:
let adView = adView(for: indexPath)
return adView.adReady ? UITableView.automaticDimension : 0
default:
return UITableView.automaticDimension
}
}
var numberOfSections: Int { public var numberOfSections: Int {
return sections.count return sections.count
} }
func numberOfRows(inSection section: Int) -> Int { public func numberOfRows(inSection section: Int) -> Int {
sections[section].numberOfRows sections[section].numberOfRows
} }
...@@ -114,8 +116,9 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -114,8 +116,9 @@ class NWSAlertCellFactory: CellFactoryProtocol {
return adView return adView
} }
let adView = adViewCache[indexPath] ?? AdView() let adView = adViewCache[indexPath] ?? AdView()
adView.delegate = self
adView.loggingAlias = "⚠️ Alert Banner" adView.loggingAlias = "⚠️ Alert Banner"
adView.set(placementName: placementNamePrecipitationBanner, adType: .banner) adView.set(placementName: placementNameNWSAlertBanner, adType: .banner)
adViewCache[indexPath] = adView adViewCache[indexPath] = adView
return adView return adView
} }
...@@ -124,12 +127,18 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -124,12 +127,18 @@ class NWSAlertCellFactory: CellFactoryProtocol {
registerCell(type: NWSAlertCell.self, tableView: tableView) registerCell(type: NWSAlertCell.self, tableView: tableView)
registerCell(type: NWSForecastOfficeTableViewCell.self, tableView: tableView) registerCell(type: NWSForecastOfficeTableViewCell.self, tableView: tableView)
registerCell(type: NWSAlertInfoBlockTableViewCell.self, tableView: tableView) registerCell(type: NWSAlertInfoBlockTableViewCell.self, tableView: tableView)
registerCell(type: AdCell.self, tableView: tableView) registerCell(type: BannerAdCell.self, tableView: tableView)
registerCell(type: MRECAdCell.self, tableView: tableView)
} }
func cellFromTableView(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell { private func cellType(at indexPath: IndexPath) -> NWSAlertCellType {
let section = sections[indexPath.section] let section = sections[indexPath.section]
let type = section.type(forRow: indexPath.row) let type = section.type(forRow: indexPath.row)
return type
}
public func cellFromTableView(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
let type = cellType(at: indexPath)
switch type { switch type {
case .header: case .header:
let alertCell = dequeueReusableCell(type: NWSAlertCell.self, tableView: tableView, indexPath: indexPath) let alertCell = dequeueReusableCell(type: NWSAlertCell.self, tableView: tableView, indexPath: indexPath)
...@@ -147,10 +156,14 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -147,10 +156,14 @@ class NWSAlertCellFactory: CellFactoryProtocol {
let extendedInfoBlockCell = dequeueReusableCell(type: NWSAlertInfoBlockTableViewCell.self, tableView: tableView, indexPath: indexPath) let extendedInfoBlockCell = dequeueReusableCell(type: NWSAlertInfoBlockTableViewCell.self, tableView: tableView, indexPath: indexPath)
extendedInfoBlockCell.configure(with: info) extendedInfoBlockCell.configure(with: info)
return extendedInfoBlockCell return extendedInfoBlockCell
case .ad: case .adBanner:
let adCell = dequeueReusableCell(type: AdCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: BannerAdCell.self, tableView: tableView, indexPath: indexPath)
adCell.adView = adView(for: indexPath) cell.adView = adView(for: indexPath)
return adCell return cell
case .adMREC:
let cell = dequeueReusableCell(type: MRECAdCell.self, tableView: tableView, indexPath: indexPath)
cell.adView = adView(for: indexPath)
return cell
} }
} }
...@@ -172,3 +185,22 @@ class NWSAlertCellFactory: CellFactoryProtocol { ...@@ -172,3 +185,22 @@ class NWSAlertCellFactory: CellFactoryProtocol {
} }
} }
} }
// MARK: - AdViewDelegate
extension NWSAlertCellFactory: AdViewDelegate {
func succeeded(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
func failed(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
}
...@@ -110,7 +110,7 @@ extension NWSAlertViewController: UITableViewDelegate, UITableViewDataSource { ...@@ -110,7 +110,7 @@ extension NWSAlertViewController: UITableViewDelegate, UITableViewDataSource {
} }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
UITableView.automaticDimension return viewModel.cellFactory.height(for: indexPath)
} }
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
......
...@@ -18,7 +18,7 @@ private struct LayerSection { ...@@ -18,7 +18,7 @@ private struct LayerSection {
let rowsCount:Int let rowsCount:Int
} }
class RadarLayersCellFactory: CellFactoryProtocol { class RadarLayersCellFactory: CellFactory {
//Private //Private
private let radarViewModel:RadarViewModel private let radarViewModel:RadarViewModel
private let sections:[LayerSection] private let sections:[LayerSection]
......
...@@ -84,7 +84,7 @@ private struct SettingsDataSource { ...@@ -84,7 +84,7 @@ private struct SettingsDataSource {
let rows:[SettingsRow] let rows:[SettingsRow]
} }
class SettingsCellFactory: CellFactoryProtocol { class SettingsCellFactory: CellFactory {
//Private //Private
private let viewModel: SettingsViewModel private let viewModel: SettingsViewModel
private let sections: [SettingsDataSource] = { private let sections: [SettingsDataSource] = {
......
...@@ -9,7 +9,7 @@ import UIKit ...@@ -9,7 +9,7 @@ import UIKit
import Localize_Swift import Localize_Swift
import OneWeatherCore import OneWeatherCore
class SettingsDetailsCellFactory: CellFactoryProtocol { class SettingsDetailsCellFactory: CellFactory {
//Private //Private
private let viewModel:SettingsDetailsViewModel private let viewModel:SettingsDetailsViewModel
......
...@@ -11,7 +11,8 @@ import OneWeatherCore ...@@ -11,7 +11,8 @@ import OneWeatherCore
public enum TodayCellType:Int { public enum TodayCellType:Int {
case alert = 0 case alert = 0
case forecast case forecast
case ad case adBanner
case adMREC
case conditions case conditions
case forecastPeriod case forecastPeriod
case precipitation case precipitation
...@@ -49,18 +50,19 @@ private struct TodaySection { ...@@ -49,18 +50,19 @@ private struct TodaySection {
} }
} }
class TodayCellFactory: CellFactoryProtocol { class TodayCellFactory: CellFactory {
//Private //Private
private var cellsToUpdate:CellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime] private var cellsToUpdate:CellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime]
private let todayViewModel:TodayViewModel private let todayViewModel:TodayViewModel
private var todaySection = TodaySection(allRows: [.alert, .forecast, .ad, private var todaySection = TodaySection(allRows: [.alert, .forecast, .adBanner,
.conditions, .forecastPeriod, .precipitation, .conditions, .forecastPeriod, .precipitation, .adMREC,
.airQuality, .dayTime, .sun, .moon]) .airQuality, .dayTime, .sun, .moon])
private var adViewCache = [IndexPath: AdView]() private var adViewCache = [IndexPath: AdView]()
//Public //Public
public var delegate: CellFactoryDelegate?
init(viewModel: TodayViewModel) { init(viewModel: TodayViewModel) {
self.todayViewModel = viewModel self.todayViewModel = viewModel
} }
...@@ -76,7 +78,8 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -76,7 +78,8 @@ class TodayCellFactory: CellFactoryProtocol {
public func registerCells(on tableView:UITableView) { public func registerCells(on tableView:UITableView) {
registerCell(type: TodayAlertCell.self, tableView: tableView) registerCell(type: TodayAlertCell.self, tableView: tableView)
registerCell(type: TodayForecastCell.self, tableView: tableView) registerCell(type: TodayForecastCell.self, tableView: tableView)
registerCell(type: AdCell.self, tableView: tableView) registerCell(type: BannerAdCell.self, tableView: tableView)
registerCell(type: MRECAdCell.self, tableView: tableView)
registerCell(type: TodayConditionsCell.self, tableView: tableView) registerCell(type: TodayConditionsCell.self, tableView: tableView)
registerCell(type: TodayForecastTimePeriodCell.self, tableView: tableView) registerCell(type: TodayForecastTimePeriodCell.self, tableView: tableView)
registerCell(type: PrecipitationCell.self, tableView: tableView) registerCell(type: PrecipitationCell.self, tableView: tableView)
...@@ -90,9 +93,15 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -90,9 +93,15 @@ class TodayCellFactory: CellFactoryProtocol {
if let adView = adViewCache[indexPath] { if let adView = adViewCache[indexPath] {
return adView return adView
} }
let adView = adViewCache[indexPath] ?? AdView() let adView = AdView()
adView.delegate = self
adView.loggingAlias = "📍 Today Banner" adView.loggingAlias = "📍 Today Banner"
adView.set(placementName: placementNameTodayBanner, adType: .banner) var adType = AdType.banner
if cellType(at: indexPath) == .adMREC {
adType = .square
adView.loggingAlias = "📅 Today MREC"
}
adView.set(placementName: placementNameTodayBanner, adType: adType)
adViewCache[indexPath] = adView adViewCache[indexPath] = adView
return adView return adView
} }
...@@ -117,16 +126,17 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -117,16 +126,17 @@ class TodayCellFactory: CellFactoryProtocol {
let cell = dequeueReusableCell(type: TodayForecastCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: TodayForecastCell.self, tableView: tableView, indexPath: indexPath)
cell.configure(with: loc) cell.configure(with: loc)
return cell return cell
case .ad: case .adBanner:
let cell = dequeueReusableCell(type: AdCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: BannerAdCell.self, tableView: tableView, indexPath: indexPath)
cell.adView = adView(for: indexPath)
return cell
case .adMREC:
let cell = dequeueReusableCell(type: MRECAdCell.self, tableView: tableView, indexPath: indexPath)
cell.adView = adView(for: indexPath) cell.adView = adView(for: indexPath)
return cell return cell
case .conditions: case .conditions:
let cell = dequeueReusableCell(type: TodayConditionsCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: TodayConditionsCell.self, tableView: tableView, indexPath: indexPath)
// if cellsToUpdate.contains(.condition) {
cell.configure(with: loc) cell.configure(with: loc)
// cellsToUpdate.remove(.condition)
// }
return cell return cell
case .forecastPeriod: case .forecastPeriod:
let cell = dequeueReusableCell(type: TodayForecastTimePeriodCell.self, tableView: tableView, indexPath: indexPath) let cell = dequeueReusableCell(type: TodayForecastTimePeriodCell.self, tableView: tableView, indexPath: indexPath)
...@@ -164,6 +174,18 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -164,6 +174,18 @@ class TodayCellFactory: CellFactoryProtocol {
} }
} }
public func height(for indexPath: IndexPath) -> CGFloat {
let cellType = cellType(at: indexPath)
switch cellType {
case .adBanner: fallthrough
case .adMREC:
let adView = adView(for: indexPath)
return adView.adReady ? UITableView.automaticDimension : 0
default:
return UITableView.automaticDimension
}
}
public func setNeedsUpdate() { public func setNeedsUpdate() {
cellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime] cellsToUpdate = [.condition, .timePeriod, .precipitation, .dayTime]
setupHiddenRows() setupHiddenRows()
...@@ -195,7 +217,8 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -195,7 +217,8 @@ class TodayCellFactory: CellFactoryProtocol {
var rowsToHide = Set<TodayCellType>() var rowsToHide = Set<TodayCellType>()
if isAppPro() || !AdConfigManager.shared.adConfig.adsEnabled { if isAppPro() || !AdConfigManager.shared.adConfig.adsEnabled {
rowsToHide.insert(.ad) rowsToHide.insert(.adBanner)
rowsToHide.insert(.adMREC)
} }
let location = self.todayViewModel.location let location = self.todayViewModel.location
...@@ -214,3 +237,22 @@ class TodayCellFactory: CellFactoryProtocol { ...@@ -214,3 +237,22 @@ class TodayCellFactory: CellFactoryProtocol {
todaySection.hiddenRows = rowsToHide todaySection.hiddenRows = rowsToHide
} }
} }
// MARK: - AdViewDelegate
extension TodayCellFactory: AdViewDelegate {
func succeeded(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
func failed(adView: AdView, hadAdBefore: Bool) {
onMain {
if hadAdBefore != adView.adReady {
self.delegate?.cellFactoryCellsChanged(self)
}
}
}
}
...@@ -107,7 +107,6 @@ private extension TodayViewController { ...@@ -107,7 +107,6 @@ private extension TodayViewController {
tableView.separatorStyle = .none tableView.separatorStyle = .none
tableView.tableFooterView = UIView() tableView.tableFooterView = UIView()
tableView.estimatedRowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.rowHeight = UITableView.automaticDimension
tableView.delegate = self tableView.delegate = self
tableView.dataSource = self tableView.dataSource = self
view.addSubview(tableView) view.addSubview(tableView)
...@@ -127,6 +126,10 @@ extension TodayViewController: UITableViewDataSource { ...@@ -127,6 +126,10 @@ extension TodayViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return viewModel.todayCellFactory.cellFromTableView(tableView: tableView, indexPath: indexPath) return viewModel.todayCellFactory.cellFromTableView(tableView: tableView, indexPath: indexPath)
} }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return viewModel.todayCellFactory.height(for: indexPath)
}
} }
//MARK:- UITableView Delegate //MARK:- UITableView Delegate
......
...@@ -25,6 +25,7 @@ class NWSAlertViewModel: ViewModelProtocol { ...@@ -25,6 +25,7 @@ class NWSAlertViewModel: ViewModelProtocol {
cellFactory = NWSAlertCellFactory(alert: alert) cellFactory = NWSAlertCellFactory(alert: alert)
alertsManager.delegates.add(delegate: self) alertsManager.delegates.add(delegate: self)
NotificationCenter.default.addObserver(self, selector: #selector(handlePremiumStateChange), name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handlePremiumStateChange), name: Notification.Name(rawValue: kEventInAppPurchasedCompleted), object: nil)
cellFactory.delegate = self
} }
@objc @objc
...@@ -35,6 +36,7 @@ class NWSAlertViewModel: ViewModelProtocol { ...@@ -35,6 +36,7 @@ class NWSAlertViewModel: ViewModelProtocol {
} }
} }
//MARK: - NWSAlertsManagerDelegate
extension NWSAlertViewModel: NWSAlertsManagerDelegate { extension NWSAlertViewModel: NWSAlertsManagerDelegate {
func alertsListDidChange(in alertsManager: NWSAlertsManager) { func alertsListDidChange(in alertsManager: NWSAlertsManager) {
// do nothing // do nothing
...@@ -48,3 +50,10 @@ extension NWSAlertViewModel: NWSAlertsManagerDelegate { ...@@ -48,3 +50,10 @@ extension NWSAlertViewModel: NWSAlertsManagerDelegate {
} }
} }
} }
extension NWSAlertViewModel: CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory) {
delegate?.viewModelDidChange(model: self)
}
}
...@@ -24,7 +24,9 @@ class TodayViewModel: ViewModelProtocol { ...@@ -24,7 +24,9 @@ class TodayViewModel: ViewModelProtocol {
private(set) var location:Location? private(set) var location:Location?
public lazy var todayCellFactory:TodayCellFactory = { public lazy var todayCellFactory:TodayCellFactory = {
TodayCellFactory(viewModel: self) let factory = TodayCellFactory(viewModel: self)
factory.delegate = self
return factory
}() }()
deinit { deinit {
...@@ -130,3 +132,10 @@ extension TodayViewModel: SettingsDelegate { ...@@ -130,3 +132,10 @@ extension TodayViewModel: SettingsDelegate {
delegate?.viewModelDidChange(model: self) delegate?.viewModelDidChange(model: self)
} }
} }
// MARK: CellFactoryDelegate
extension TodayViewModel: CellFactoryDelegate {
func cellFactoryCellsChanged(_ factory: CellFactory) {
delegate?.viewModelDidChange(model: self)
}
}
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