From d24b9f8693a2d868035b6b60260872eeacb0ec7d Mon Sep 17 00:00:00 2001 From: richashukla Date: Mon, 31 Aug 2020 19:31:38 -0700 Subject: [PATCH] feat/remove references to native and mrec in demo app (#31) * Remove references to native and mrec in demo app - Obj C * Remove references to native and mrec in demo app * Revert "Remove references to native and mrec in demo app" This reverts commit c57dadb2ea1db7c50183efd2f0713e9c5e83c443. * Remove references to native and mrec in demo app - Swift * Running pod deintegrate and updating DEVELOPMENT_TEAM to match master for both projects * Remove MRECs.storyboard * More pbxproj updates --- .../project.pbxproj | 262 +------ ...ALDemoInterfaceBuilderMRECViewController.h | 14 - ...ALDemoInterfaceBuilderMRECViewController.m | 99 --- .../ALDemoProgrammaticMRECViewController.h | 13 - .../ALDemoProgrammaticMRECViewController.m | 166 ----- .../ALDemoNativeAdFeedTableViewController.h | 13 - .../ALDemoNativeAdFeedTableViewController.m | 98 --- .../Feed/Carousel UI/ALCarouselCardState.h | 52 -- .../Feed/Carousel UI/ALCarouselCardState.m | 34 - .../Carousel UI/ALCarouselRenderingProtocol.h | 26 - .../Feed/Carousel UI/ALCarouselViewModel.h | 32 - .../Feed/Carousel UI/ALCarouselViewModel.m | 174 ----- .../Feed/Carousel UI/ALNativeAdVideoPlayer.h | 30 - .../Feed/Carousel UI/ALNativeAdVideoPlayer.m | 67 -- .../Carousel UI/Assets/Star_Sprite_0.5.png | Bin 3806 -> 0 bytes .../Feed/Carousel UI/Assets/Star_Sprite_0.png | Bin 3797 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_1.5.png | Bin 3784 -> 0 bytes .../Feed/Carousel UI/Assets/Star_Sprite_1.png | Bin 3738 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_2.5.png | Bin 3734 -> 0 bytes .../Feed/Carousel UI/Assets/Star_Sprite_2.png | Bin 3793 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_3.5.png | Bin 3810 -> 0 bytes .../Feed/Carousel UI/Assets/Star_Sprite_3.png | Bin 3808 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_4.5.png | Bin 3749 -> 0 bytes .../Feed/Carousel UI/Assets/Star_Sprite_4.png | Bin 3749 -> 0 bytes .../Feed/Carousel UI/Assets/Star_Sprite_5.png | Bin 3849 -> 0 bytes .../Assets/applovin_card_learn_more.png | Bin 11806 -> 0 bytes .../Assets/applovin_card_muted.png | Bin 6592 -> 0 bytes .../Carousel UI/Assets/applovin_card_play.png | Bin 10380 -> 0 bytes .../Assets/applovin_card_replay.png | Bin 15399 -> 0 bytes .../Assets/applovin_card_unmuted.png | Bin 5483 -> 0 bytes .../Categories/ALCarouselView+Internal.h | 20 - .../Categories/UIView+ALActivityIndicator.h | 37 - .../Categories/UIView+ALActivityIndicator.m | 87 --- .../ALCarouselViewSettings.h | 86 --- .../Carousel UI/Views/ALCarouselCardView.h | 54 -- .../Carousel UI/Views/ALCarouselCardView.m | 353 ---------- .../Carousel UI/Views/ALCarouselMediaView.h | 36 - .../Carousel UI/Views/ALCarouselMediaView.m | 598 ---------------- .../Views/ALCarouselReplayOverlayView.h | 29 - .../Views/ALCarouselReplayOverlayView.m | 99 --- .../Feed/Carousel UI/Views/ALCarouselView.h | 34 - .../Feed/Carousel UI/Views/ALCarouselView.m | 642 ----------------- .../Carousel UI/Views/ALNativeAdVideoView.h | 23 - .../Carousel UI/Views/ALNativeAdVideoView.m | 48 -- .../Feed/RSS Feed Parsing/ALDemoArticle.h | 25 - .../Feed/RSS Feed Parsing/ALDemoArticle.m | 13 - .../RSS Feed Parsing/ALDemoRSSFeedRetriever.h | 23 - .../RSS Feed Parsing/ALDemoRSSFeedRetriever.m | 121 ---- ...ALDemoNativeAdProgrammaticViewController.h | 26 - ...ALDemoNativeAdProgrammaticViewController.m | 174 ----- .../Base.lproj/Main.storyboard | 130 +--- .../Supporting Files/MRECs.storyboard | 205 ------ .../project.pbxproj | 250 +------ ...moInterfaceBuilderMRecViewController.swift | 108 --- ...ALDemoProgrammaticMRecViewController.swift | 122 ---- ...LDemoNativeAdFeedTableViewController.swift | 94 --- .../Feed /Carousel UI/ALCarouselCardState.h | 52 -- .../Feed /Carousel UI/ALCarouselCardState.m | 34 - .../Carousel UI/ALCarouselRenderingProtocol.h | 26 - .../Feed /Carousel UI/ALCarouselViewModel.h | 32 - .../Feed /Carousel UI/ALCarouselViewModel.m | 175 ----- .../Native/Feed /Carousel UI/ALDebugLog.h | 18 - .../Feed /Carousel UI/ALNativeAdVideoPlayer.h | 30 - .../Feed /Carousel UI/ALNativeAdVideoPlayer.m | 67 -- .../Carousel UI/Assets/Star_Sprite_0.5.png | Bin 3806 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_0.png | Bin 3797 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_1.5.png | Bin 3784 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_1.png | Bin 3738 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_2.5.png | Bin 3734 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_2.png | Bin 3793 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_3.5.png | Bin 3810 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_3.png | Bin 3808 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_4.5.png | Bin 3749 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_4.png | Bin 3749 -> 0 bytes .../Carousel UI/Assets/Star_Sprite_5.png | Bin 3849 -> 0 bytes .../Assets/applovin_card_learn_more.png | Bin 11806 -> 0 bytes .../Assets/applovin_card_muted.png | Bin 6592 -> 0 bytes .../Carousel UI/Assets/applovin_card_play.png | Bin 10380 -> 0 bytes .../Assets/applovin_card_replay.png | Bin 15399 -> 0 bytes .../Assets/applovin_card_unmuted.png | Bin 5483 -> 0 bytes .../Categories/ALCarouselView+Internal.h | 20 - .../Categories/UIView+ALActivityIndicator.h | 37 - .../Categories/UIView+ALActivityIndicator.m | 88 --- .../ALCarouselViewSettings.h | 86 --- .../Carousel UI/Views/ALCarouselCardView.h | 54 -- .../Carousel UI/Views/ALCarouselCardView.m | 354 ---------- .../Carousel UI/Views/ALCarouselMediaView.h | 36 - .../Carousel UI/Views/ALCarouselMediaView.m | 599 ---------------- .../Views/ALCarouselReplayOverlayView.h | 29 - .../Views/ALCarouselReplayOverlayView.m | 99 --- .../Feed /Carousel UI/Views/ALCarouselView.h | 34 - .../Feed /Carousel UI/Views/ALCarouselView.m | 643 ------------------ .../Carousel UI/Views/ALNativeAdVideoView.h | 23 - .../Carousel UI/Views/ALNativeAdVideoView.m | 48 -- .../Feed /RSS Feed Parsing/ALDemoArticle.h | 25 - .../Feed /RSS Feed Parsing/ALDemoArticle.m | 13 - .../RSS Feed Parsing/ALDemoRSSFeedRetriever.h | 23 - .../RSS Feed Parsing/ALDemoRSSFeedRetriever.m | 121 ---- ...moNativeAdProgrammaticViewController.swift | 193 ------ .../Base.lproj/Main.storyboard | 64 +- .../Supporting Files/MRECs.storyboard | 205 ------ .../AppLovin MAX Demo App-Bridging-Header.h | 4 - README.md | 2 + 103 files changed, 28 insertions(+), 7723 deletions(-) delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselRenderingProtocol.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_0.5.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_0.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_1.5.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_1.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_2.5.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_2.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_3.5.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_3.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_4.5.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_4.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_5.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_learn_more.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_muted.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_play.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_replay.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_unmuted.png delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Categories/ALCarouselView+Internal.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Categories/UIView+ALActivityIndicator.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Categories/UIView+ALActivityIndicator.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.h delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.m delete mode 100644 AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/Supporting Files/MRECs.storyboard delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/MRECs/ALDemoInterfaceBuilderMRecViewController.swift delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/MRECs/ALDemoProgrammaticMRecViewController.swift delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /ALDemoNativeAdFeedTableViewController.swift delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALCarouselCardState.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALCarouselCardState.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALCarouselRenderingProtocol.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALCarouselViewModel.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALCarouselViewModel.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALDebugLog.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALNativeAdVideoPlayer.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/ALNativeAdVideoPlayer.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_0.5.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_0.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_1.5.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_1.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_2.5.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_2.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_3.5.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_3.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_4.5.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_4.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/Star_Sprite_5.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_learn_more.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_muted.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_play.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_replay.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_unmuted.png delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Categories/ALCarouselView+Internal.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Categories/UIView+ALActivityIndicator.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Categories/UIView+ALActivityIndicator.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.h delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.m delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Programattic/ALDemoNativeAdProgrammaticViewController.swift delete mode 100644 AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/MRECs.storyboard diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC.xcodeproj/project.pbxproj b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC.xcodeproj/project.pbxproj index fd67db8741..d94ef823c8 100644 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC.xcodeproj/project.pbxproj +++ b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -32,43 +32,11 @@ E56785F423F35B8F00ACA6C1 /* Leaders.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E56785F323F35B8F00ACA6C1 /* Leaders.storyboard */; }; E56785F923F35BC200ACA6C1 /* ALDemoInterfaceBuilderLeaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56785F723F35BC200ACA6C1 /* ALDemoInterfaceBuilderLeaderViewController.m */; }; E56785FA23F35BC200ACA6C1 /* ALDemoProgrammaticLeaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56785F823F35BC200ACA6C1 /* ALDemoProgrammaticLeaderViewController.m */; }; - E56785FF23F4846000ACA6C1 /* MRECs.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E56785FE23F4846000ACA6C1 /* MRECs.storyboard */; }; - E567860223F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E567860023F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.m */; }; - E567860623F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E567860423F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.m */; }; - E56786B823F48B2000ACA6C1 /* ALCarouselCardView.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786AE23F48B1F00ACA6C1 /* ALCarouselCardView.m */; }; - E56786B923F48B2000ACA6C1 /* ALCarouselReplayOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786AF23F48B1F00ACA6C1 /* ALCarouselReplayOverlayView.m */; }; - E56786BA23F48B2000ACA6C1 /* ALCarouselMediaView.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786B323F48B2000ACA6C1 /* ALCarouselMediaView.m */; }; - E56786BB23F48B2000ACA6C1 /* ALCarouselView.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786B523F48B2000ACA6C1 /* ALCarouselView.m */; }; - E56786BC23F48B2000ACA6C1 /* ALNativeAdVideoView.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786B723F48B2000ACA6C1 /* ALNativeAdVideoView.m */; }; - E56786C223F48B7500ACA6C1 /* UIView+ALActivityIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786C023F48B7400ACA6C1 /* UIView+ALActivityIndicator.m */; }; - E56786CA23F48B8A00ACA6C1 /* ALCarouselCardState.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786C323F48B8900ACA6C1 /* ALCarouselCardState.m */; }; - E56786CB23F48B8A00ACA6C1 /* ALNativeAdVideoPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786C523F48B8900ACA6C1 /* ALNativeAdVideoPlayer.m */; }; - E56786CC23F48B8A00ACA6C1 /* ALCarouselViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786C823F48B8A00ACA6C1 /* ALCarouselViewModel.m */; }; - E56786D123F48C1A00ACA6C1 /* ALDemoArticle.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786CE23F48C1A00ACA6C1 /* ALDemoArticle.m */; }; - E56786D223F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786CF23F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.m */; }; - E56786D723F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786D623F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.m */; }; - E56786E823F4C24500ACA6C1 /* Star_Sprite_4.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786D823F4C24500ACA6C1 /* Star_Sprite_4.png */; }; - E56786E923F4C24500ACA6C1 /* Star_Sprite_3.5.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786D923F4C24500ACA6C1 /* Star_Sprite_3.5.png */; }; - E56786EA23F4C24500ACA6C1 /* Star_Sprite_1.5.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786DA23F4C24500ACA6C1 /* Star_Sprite_1.5.png */; }; - E56786EB23F4C24500ACA6C1 /* Star_Sprite_5.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786DB23F4C24500ACA6C1 /* Star_Sprite_5.png */; }; - E56786EC23F4C24500ACA6C1 /* Star_Sprite_0.5.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786DC23F4C24500ACA6C1 /* Star_Sprite_0.5.png */; }; - E56786ED23F4C24500ACA6C1 /* Star_Sprite_1.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786DD23F4C24500ACA6C1 /* Star_Sprite_1.png */; }; - E56786EE23F4C24500ACA6C1 /* Star_Sprite_2.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786DE23F4C24500ACA6C1 /* Star_Sprite_2.png */; }; - E56786EF23F4C24500ACA6C1 /* Star_Sprite_4.5.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786DF23F4C24500ACA6C1 /* Star_Sprite_4.5.png */; }; - E56786F023F4C24500ACA6C1 /* applovin_card_muted.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E023F4C24500ACA6C1 /* applovin_card_muted.png */; }; - E56786F123F4C24500ACA6C1 /* applovin_card_play.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E123F4C24500ACA6C1 /* applovin_card_play.png */; }; - E56786F223F4C24500ACA6C1 /* Star_Sprite_0.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E223F4C24500ACA6C1 /* Star_Sprite_0.png */; }; - E56786F323F4C24500ACA6C1 /* applovin_card_replay.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E323F4C24500ACA6C1 /* applovin_card_replay.png */; }; - E56786F423F4C24500ACA6C1 /* Star_Sprite_2.5.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E423F4C24500ACA6C1 /* Star_Sprite_2.5.png */; }; - E56786F523F4C24500ACA6C1 /* Star_Sprite_3.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E523F4C24500ACA6C1 /* Star_Sprite_3.png */; }; - E56786F623F4C24500ACA6C1 /* applovin_card_learn_more.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E623F4C24500ACA6C1 /* applovin_card_learn_more.png */; }; - E56786F723F4C24500ACA6C1 /* applovin_card_unmuted.png in Resources */ = {isa = PBXBuildFile; fileRef = E56786E723F4C24500ACA6C1 /* applovin_card_unmuted.png */; }; E56786FA23F4CAE100ACA6C1 /* ALEventTrackingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56786F823F4CAE000ACA6C1 /* ALEventTrackingViewController.m */; }; E57306F123EB90D500D972F4 /* Interstitials.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E57306F023EB90D500D972F4 /* Interstitials.storyboard */; }; E573083123EB96E400D972F4 /* ALDemoInterstitialBasicIntegrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E573083023EB96E400D972F4 /* ALDemoInterstitialBasicIntegrationViewController.m */; }; E573083423EB970400D972F4 /* ALDemoInterstitialManualLoadingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E573083323EB970400D972F4 /* ALDemoInterstitialManualLoadingViewController.m */; }; E573083823EB972C00D972F4 /* ALDemoInterstitalZoneViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E573083723EB972C00D972F4 /* ALDemoInterstitalZoneViewController.m */; }; - E5C8F4C724119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E5C8F4C624119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -117,54 +85,6 @@ E56785F623F35BC200ACA6C1 /* ALDemoInterfaceBuilderLeaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoInterfaceBuilderLeaderViewController.h; sourceTree = ""; }; E56785F723F35BC200ACA6C1 /* ALDemoInterfaceBuilderLeaderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoInterfaceBuilderLeaderViewController.m; sourceTree = ""; }; E56785F823F35BC200ACA6C1 /* ALDemoProgrammaticLeaderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoProgrammaticLeaderViewController.m; sourceTree = ""; }; - E56785FE23F4846000ACA6C1 /* MRECs.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MRECs.storyboard; sourceTree = ""; }; - E567860023F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoProgrammaticMRECViewController.m; sourceTree = ""; }; - E567860123F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoProgrammaticMRECViewController.h; sourceTree = ""; }; - E567860423F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoNativeAdProgrammaticViewController.m; sourceTree = ""; }; - E567860523F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoNativeAdProgrammaticViewController.h; sourceTree = ""; }; - E567860923F48A1A00ACA6C1 /* ALCarouselViewSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALCarouselViewSettings.h; sourceTree = ""; }; - E56786AE23F48B1F00ACA6C1 /* ALCarouselCardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALCarouselCardView.m; sourceTree = ""; }; - E56786AF23F48B1F00ACA6C1 /* ALCarouselReplayOverlayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALCarouselReplayOverlayView.m; sourceTree = ""; }; - E56786B023F48B1F00ACA6C1 /* ALCarouselCardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselCardView.h; sourceTree = ""; }; - E56786B123F48B2000ACA6C1 /* ALNativeAdVideoView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALNativeAdVideoView.h; sourceTree = ""; }; - E56786B223F48B2000ACA6C1 /* ALCarouselMediaView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselMediaView.h; sourceTree = ""; }; - E56786B323F48B2000ACA6C1 /* ALCarouselMediaView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALCarouselMediaView.m; sourceTree = ""; }; - E56786B423F48B2000ACA6C1 /* ALCarouselView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselView.h; sourceTree = ""; }; - E56786B523F48B2000ACA6C1 /* ALCarouselView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALCarouselView.m; sourceTree = ""; }; - E56786B623F48B2000ACA6C1 /* ALCarouselReplayOverlayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselReplayOverlayView.h; sourceTree = ""; }; - E56786B723F48B2000ACA6C1 /* ALNativeAdVideoView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALNativeAdVideoView.m; sourceTree = ""; }; - E56786BF23F48B7400ACA6C1 /* UIView+ALActivityIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ALActivityIndicator.h"; sourceTree = ""; }; - E56786C023F48B7400ACA6C1 /* UIView+ALActivityIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ALActivityIndicator.m"; sourceTree = ""; }; - E56786C123F48B7500ACA6C1 /* ALCarouselView+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALCarouselView+Internal.h"; sourceTree = ""; }; - E56786C323F48B8900ACA6C1 /* ALCarouselCardState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALCarouselCardState.m; sourceTree = ""; }; - E56786C423F48B8900ACA6C1 /* ALNativeAdVideoPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALNativeAdVideoPlayer.h; sourceTree = ""; }; - E56786C523F48B8900ACA6C1 /* ALNativeAdVideoPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALNativeAdVideoPlayer.m; sourceTree = ""; }; - E56786C623F48B8900ACA6C1 /* ALCarouselCardState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselCardState.h; sourceTree = ""; }; - E56786C723F48B8A00ACA6C1 /* ALCarouselViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselViewModel.h; sourceTree = ""; }; - E56786C823F48B8A00ACA6C1 /* ALCarouselViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALCarouselViewModel.m; sourceTree = ""; }; - E56786C923F48B8A00ACA6C1 /* ALCarouselRenderingProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALCarouselRenderingProtocol.h; sourceTree = ""; }; - E56786CD23F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoRSSFeedRetriever.h; sourceTree = ""; }; - E56786CE23F48C1A00ACA6C1 /* ALDemoArticle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoArticle.m; sourceTree = ""; }; - E56786CF23F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoRSSFeedRetriever.m; sourceTree = ""; }; - E56786D023F48C1A00ACA6C1 /* ALDemoArticle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoArticle.h; sourceTree = ""; }; - E56786D523F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoNativeAdFeedTableViewController.h; sourceTree = ""; }; - E56786D623F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoNativeAdFeedTableViewController.m; sourceTree = ""; }; - E56786D823F4C24500ACA6C1 /* Star_Sprite_4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_4.png; sourceTree = ""; }; - E56786D923F4C24500ACA6C1 /* Star_Sprite_3.5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_3.5.png; sourceTree = ""; }; - E56786DA23F4C24500ACA6C1 /* Star_Sprite_1.5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_1.5.png; sourceTree = ""; }; - E56786DB23F4C24500ACA6C1 /* Star_Sprite_5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_5.png; sourceTree = ""; }; - E56786DC23F4C24500ACA6C1 /* Star_Sprite_0.5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_0.5.png; sourceTree = ""; }; - E56786DD23F4C24500ACA6C1 /* Star_Sprite_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_1.png; sourceTree = ""; }; - E56786DE23F4C24500ACA6C1 /* Star_Sprite_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_2.png; sourceTree = ""; }; - E56786DF23F4C24500ACA6C1 /* Star_Sprite_4.5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_4.5.png; sourceTree = ""; }; - E56786E023F4C24500ACA6C1 /* applovin_card_muted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = applovin_card_muted.png; sourceTree = ""; }; - E56786E123F4C24500ACA6C1 /* applovin_card_play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = applovin_card_play.png; sourceTree = ""; }; - E56786E223F4C24500ACA6C1 /* Star_Sprite_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_0.png; sourceTree = ""; }; - E56786E323F4C24500ACA6C1 /* applovin_card_replay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = applovin_card_replay.png; sourceTree = ""; }; - E56786E423F4C24500ACA6C1 /* Star_Sprite_2.5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_2.5.png; sourceTree = ""; }; - E56786E523F4C24500ACA6C1 /* Star_Sprite_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Star_Sprite_3.png; sourceTree = ""; }; - E56786E623F4C24500ACA6C1 /* applovin_card_learn_more.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = applovin_card_learn_more.png; sourceTree = ""; }; - E56786E723F4C24500ACA6C1 /* applovin_card_unmuted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = applovin_card_unmuted.png; sourceTree = ""; }; E56786F823F4CAE000ACA6C1 /* ALEventTrackingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALEventTrackingViewController.m; sourceTree = ""; }; E56786F923F4CAE000ACA6C1 /* ALEventTrackingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALEventTrackingViewController.h; sourceTree = ""; }; E57306F023EB90D500D972F4 /* Interstitials.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Interstitials.storyboard; sourceTree = ""; }; @@ -174,8 +94,6 @@ E573083323EB970400D972F4 /* ALDemoInterstitialManualLoadingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoInterstitialManualLoadingViewController.m; sourceTree = ""; }; E573083623EB972C00D972F4 /* ALDemoInterstitalZoneViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALDemoInterstitalZoneViewController.h; sourceTree = ""; }; E573083723EB972C00D972F4 /* ALDemoInterstitalZoneViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALDemoInterstitalZoneViewController.m; sourceTree = ""; }; - E5C8F4C524119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALDemoInterfaceBuilderMRECViewController.h; sourceTree = ""; }; - E5C8F4C624119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALDemoInterfaceBuilderMRECViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -283,7 +201,6 @@ E56784A523F22AB300ACA6C1 /* Rewarded.storyboard */, E567854A23F3541100ACA6C1 /* Banners.storyboard */, E56785F323F35B8F00ACA6C1 /* Leaders.storyboard */, - E56785FE23F4846000ACA6C1 /* MRECs.storyboard */, ); path = "Supporting Files"; sourceTree = ""; @@ -392,131 +309,6 @@ path = Programmatic; sourceTree = ""; }; - E567860323F484D200ACA6C1 /* MRECs */ = { - isa = PBXGroup; - children = ( - E5C8F4C82411B17B00592BF8 /* Programmatic */, - E5C8F4C92411B18B00592BF8 /* Interface Builder */, - ); - path = MRECs; - sourceTree = ""; - }; - E567860723F489C100ACA6C1 /* Native Ads */ = { - isa = PBXGroup; - children = ( - E567860823F489DF00ACA6C1 /* Programmatic */, - E56786D423F48C5E00ACA6C1 /* Feed */, - ); - path = "Native Ads"; - sourceTree = ""; - }; - E567860823F489DF00ACA6C1 /* Programmatic */ = { - isa = PBXGroup; - children = ( - E567860523F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.h */, - E567860423F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.m */, - ); - path = Programmatic; - sourceTree = ""; - }; - E567860A23F48A2B00ACA6C1 /* Carousel UI */ = { - isa = PBXGroup; - children = ( - E56786BD23F48B2A00ACA6C1 /* Views */, - E56786BE23F48B6600ACA6C1 /* Categories */, - E567866D23F48AC800ACA6C1 /* Assets */, - E567860B23F48A3400ACA6C1 /* Customizable SETTINGS */, - E56786C623F48B8900ACA6C1 /* ALCarouselCardState.h */, - E56786C323F48B8900ACA6C1 /* ALCarouselCardState.m */, - E56786C923F48B8A00ACA6C1 /* ALCarouselRenderingProtocol.h */, - E56786C723F48B8A00ACA6C1 /* ALCarouselViewModel.h */, - E56786C823F48B8A00ACA6C1 /* ALCarouselViewModel.m */, - E56786C423F48B8900ACA6C1 /* ALNativeAdVideoPlayer.h */, - E56786C523F48B8900ACA6C1 /* ALNativeAdVideoPlayer.m */, - ); - path = "Carousel UI"; - sourceTree = ""; - }; - E567860B23F48A3400ACA6C1 /* Customizable SETTINGS */ = { - isa = PBXGroup; - children = ( - E567860923F48A1A00ACA6C1 /* ALCarouselViewSettings.h */, - ); - path = "Customizable SETTINGS"; - sourceTree = ""; - }; - E567866D23F48AC800ACA6C1 /* Assets */ = { - isa = PBXGroup; - children = ( - E56786E623F4C24500ACA6C1 /* applovin_card_learn_more.png */, - E56786E023F4C24500ACA6C1 /* applovin_card_muted.png */, - E56786E123F4C24500ACA6C1 /* applovin_card_play.png */, - E56786E323F4C24500ACA6C1 /* applovin_card_replay.png */, - E56786E723F4C24500ACA6C1 /* applovin_card_unmuted.png */, - E56786DC23F4C24500ACA6C1 /* Star_Sprite_0.5.png */, - E56786E223F4C24500ACA6C1 /* Star_Sprite_0.png */, - E56786DA23F4C24500ACA6C1 /* Star_Sprite_1.5.png */, - E56786DD23F4C24500ACA6C1 /* Star_Sprite_1.png */, - E56786E423F4C24500ACA6C1 /* Star_Sprite_2.5.png */, - E56786DE23F4C24500ACA6C1 /* Star_Sprite_2.png */, - E56786D923F4C24500ACA6C1 /* Star_Sprite_3.5.png */, - E56786E523F4C24500ACA6C1 /* Star_Sprite_3.png */, - E56786DF23F4C24500ACA6C1 /* Star_Sprite_4.5.png */, - E56786D823F4C24500ACA6C1 /* Star_Sprite_4.png */, - E56786DB23F4C24500ACA6C1 /* Star_Sprite_5.png */, - ); - path = Assets; - sourceTree = ""; - }; - E56786BD23F48B2A00ACA6C1 /* Views */ = { - isa = PBXGroup; - children = ( - E56786B023F48B1F00ACA6C1 /* ALCarouselCardView.h */, - E56786AE23F48B1F00ACA6C1 /* ALCarouselCardView.m */, - E56786B223F48B2000ACA6C1 /* ALCarouselMediaView.h */, - E56786B323F48B2000ACA6C1 /* ALCarouselMediaView.m */, - E56786B623F48B2000ACA6C1 /* ALCarouselReplayOverlayView.h */, - E56786AF23F48B1F00ACA6C1 /* ALCarouselReplayOverlayView.m */, - E56786B423F48B2000ACA6C1 /* ALCarouselView.h */, - E56786B523F48B2000ACA6C1 /* ALCarouselView.m */, - E56786B123F48B2000ACA6C1 /* ALNativeAdVideoView.h */, - E56786B723F48B2000ACA6C1 /* ALNativeAdVideoView.m */, - ); - path = Views; - sourceTree = ""; - }; - E56786BE23F48B6600ACA6C1 /* Categories */ = { - isa = PBXGroup; - children = ( - E56786C123F48B7500ACA6C1 /* ALCarouselView+Internal.h */, - E56786BF23F48B7400ACA6C1 /* UIView+ALActivityIndicator.h */, - E56786C023F48B7400ACA6C1 /* UIView+ALActivityIndicator.m */, - ); - path = Categories; - sourceTree = ""; - }; - E56786D323F48C2200ACA6C1 /* RSS Feed Parsing */ = { - isa = PBXGroup; - children = ( - E56786D023F48C1A00ACA6C1 /* ALDemoArticle.h */, - E56786CE23F48C1A00ACA6C1 /* ALDemoArticle.m */, - E56786CD23F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.h */, - E56786CF23F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.m */, - ); - path = "RSS Feed Parsing"; - sourceTree = ""; - }; - E56786D423F48C5E00ACA6C1 /* Feed */ = { - isa = PBXGroup; - children = ( - E567860A23F48A2B00ACA6C1 /* Carousel UI */, - E56786D323F48C2200ACA6C1 /* RSS Feed Parsing */, - E56786D523F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.h */, - E56786D623F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.m */, - ); - path = Feed; - sourceTree = ""; - }; E56786FB23F4CAE700ACA6C1 /* Event Tracking */ = { isa = PBXGroup; children = ( @@ -533,8 +325,6 @@ E56786FB23F4CAE700ACA6C1 /* Event Tracking */, E573083A23EB975500D972F4 /* Interstitials */, E56785FB23F35BCA00ACA6C1 /* Leaders */, - E567860323F484D200ACA6C1 /* MRECs */, - E567860723F489C100ACA6C1 /* Native Ads */, E567854723F22E1E00ACA6C1 /* Rewarded */, ); path = AppLovin; @@ -577,24 +367,6 @@ path = Interstitials; sourceTree = ""; }; - E5C8F4C82411B17B00592BF8 /* Programmatic */ = { - isa = PBXGroup; - children = ( - E567860123F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.h */, - E567860023F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.m */, - ); - path = Programmatic; - sourceTree = ""; - }; - E5C8F4C92411B18B00592BF8 /* Interface Builder */ = { - isa = PBXGroup; - children = ( - E5C8F4C524119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.h */, - E5C8F4C624119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.m */, - ); - path = "Interface Builder"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -652,30 +424,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - E56786EC23F4C24500ACA6C1 /* Star_Sprite_0.5.png in Resources */, - E56786F623F4C24500ACA6C1 /* applovin_card_learn_more.png in Resources */, 1D992FEB231FA1C500C472F8 /* LaunchScreen.storyboard in Resources */, - E56785FF23F4846000ACA6C1 /* MRECs.storyboard in Resources */, - E56786F223F4C24500ACA6C1 /* Star_Sprite_0.png in Resources */, E56785F423F35B8F00ACA6C1 /* Leaders.storyboard in Resources */, - E56786F123F4C24500ACA6C1 /* applovin_card_play.png in Resources */, 1D992FE8231FA1C500C472F8 /* Assets.xcassets in Resources */, - E56786EB23F4C24500ACA6C1 /* Star_Sprite_5.png in Resources */, E56784A623F22AB300ACA6C1 /* Rewarded.storyboard in Resources */, - E56786F323F4C24500ACA6C1 /* applovin_card_replay.png in Resources */, - E56786F523F4C24500ACA6C1 /* Star_Sprite_3.png in Resources */, - E56786EA23F4C24500ACA6C1 /* Star_Sprite_1.5.png in Resources */, - E56786ED23F4C24500ACA6C1 /* Star_Sprite_1.png in Resources */, E57306F123EB90D500D972F4 /* Interstitials.storyboard in Resources */, - E56786EE23F4C24500ACA6C1 /* Star_Sprite_2.png in Resources */, E567854B23F3541100ACA6C1 /* Banners.storyboard in Resources */, - E56786F423F4C24500ACA6C1 /* Star_Sprite_2.5.png in Resources */, - E56786EF23F4C24500ACA6C1 /* Star_Sprite_4.5.png in Resources */, - E56786E823F4C24500ACA6C1 /* Star_Sprite_4.png in Resources */, 1D992FE6231FA1C400C472F8 /* Main.storyboard in Resources */, - E56786F023F4C24500ACA6C1 /* applovin_card_muted.png in Resources */, - E56786E923F4C24500ACA6C1 /* Star_Sprite_3.5.png in Resources */, - E56786F723F4C24500ACA6C1 /* applovin_card_unmuted.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -687,43 +442,28 @@ buildActionMask = 2147483647; files = ( C0DE8BB3234E8A86004B0CFC /* ALBaseAdViewController.m in Sources */, - E56786B823F48B2000ACA6C1 /* ALCarouselCardView.m in Sources */, 37C7E1F62329742E002165B5 /* ALHomeViewController.m in Sources */, E567854523F22E1300ACA6C1 /* ALDemoRewardedVideosViewController.m in Sources */, 37C7E1F523297423002165B5 /* main.m in Sources */, E56785EE23F3557B00ACA6C1 /* ALDemoBannerZoneViewController.m in Sources */, - E56786CA23F48B8A00ACA6C1 /* ALCarouselCardState.m in Sources */, E56785E823F3555A00ACA6C1 /* ALDemoProgrammaticBannerViewController.m in Sources */, E567854623F22E1300ACA6C1 /* ALDemoRewardedVideosZoneViewController.m in Sources */, - E56786D223F48C1A00ACA6C1 /* ALDemoRSSFeedRetriever.m in Sources */, 37B6CEDB246E05D00068A6A4 /* ALMAXInterfaceBuilderMRecAdViewController.m in Sources */, E56785EB23F3557100ACA6C1 /* ALDemoInterfaceBuilderBannerViewController.m in Sources */, 37C7E1F3232892CF002165B5 /* ALAppDelegate.m in Sources */, - E56786D123F48C1A00ACA6C1 /* ALDemoArticle.m in Sources */, E56786FA23F4CAE100ACA6C1 /* ALEventTrackingViewController.m in Sources */, - E56786B923F48B2000ACA6C1 /* ALCarouselReplayOverlayView.m in Sources */, E573083823EB972C00D972F4 /* ALDemoInterstitalZoneViewController.m in Sources */, - E56786BB23F48B2000ACA6C1 /* ALCarouselView.m in Sources */, 37B6CED5246E04FC0068A6A4 /* ALMAXAutoLayoutMRecAdViewController.m in Sources */, - E56786CB23F48B8A00ACA6C1 /* ALNativeAdVideoPlayer.m in Sources */, 37C7E1EB2328904E002165B5 /* ALMAXAutoLayoutBannerAdViewController.m in Sources */, - E567860623F4899600ACA6C1 /* ALDemoNativeAdProgrammaticViewController.m in Sources */, - E5C8F4C724119F0F00592BF8 /* ALDemoInterfaceBuilderMRECViewController.m in Sources */, E56785FA23F35BC200ACA6C1 /* ALDemoProgrammaticLeaderViewController.m in Sources */, 37B6CED8246E05770068A6A4 /* ALMAXFrameLayoutMRecAdViewController.m in Sources */, 37C7E1EC2328904E002165B5 /* ALMAXFrameLayoutBannerAdViewController.m in Sources */, - E56786BC23F48B2000ACA6C1 /* ALNativeAdVideoView.m in Sources */, - E56786C223F48B7500ACA6C1 /* UIView+ALActivityIndicator.m in Sources */, E573083423EB970400D972F4 /* ALDemoInterstitialManualLoadingViewController.m in Sources */, - E56786D723F48C7400ACA6C1 /* ALDemoNativeAdFeedTableViewController.m in Sources */, 37C7E1ED2328904E002165B5 /* ALMAXInterstitialAdViewController.m in Sources */, 37C7E1EE2328904E002165B5 /* ALMAXRewardedAdViewController.m in Sources */, E56785F923F35BC200ACA6C1 /* ALDemoInterfaceBuilderLeaderViewController.m in Sources */, - E56786CC23F48B8A00ACA6C1 /* ALCarouselViewModel.m in Sources */, E573083123EB96E400D972F4 /* ALDemoInterstitialBasicIntegrationViewController.m in Sources */, 37C7E1EF2328904E002165B5 /* ALMAXInterfaceBuilderBannerAdViewController.m in Sources */, - E56786BA23F48B2000ACA6C1 /* ALCarouselMediaView.m in Sources */, - E567860223F484C900ACA6C1 /* ALDemoProgrammaticMRECViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.h deleted file mode 100644 index b03f0fa026..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// ALDemoInterfaceBuilderMRECViewController.h -// AppLovin Demo App - ObjC -// -// Created by Varsha Hanji on 3/5/20. -// Copyright © 2020 AppLovin Corporation. All rights reserved. -// - -#import "ALBaseAdViewController.h" - -@interface ALDemoInterfaceBuilderMRECViewController : ALBaseAdViewController - -@end - diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.m deleted file mode 100644 index 0173277dde..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Interface Builder/ALDemoInterfaceBuilderMRECViewController.m +++ /dev/null @@ -1,99 +0,0 @@ -// -// ALDemoInterfaceBuilderMRECViewController.m -// AppLovin Demo App - ObjC -// -// Created by Varsha Hanji on 3/5/20. -// Copyright © 2020 AppLovin Corporation. All rights reserved. -// - -#import "ALDemoInterfaceBuilderMRECViewController.h" -#import - -@interface ALDemoInterfaceBuilderMRECViewController () -@property (weak, nonatomic) IBOutlet ALAdView *adView; -@end - -@implementation ALDemoInterfaceBuilderMRECViewController - -#pragma mark - View Lifecycle - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear: animated]; - - self.adView.adLoadDelegate = self; - self.adView.adDisplayDelegate = self; - self.adView.adEventDelegate = self; - - // Call loadNextAd() to start showing ads - self.adView.adSize = ALAdSize.mrec; - [self.adView loadNextAd]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear: animated]; - - self.adView.adLoadDelegate = nil; - self.adView.adDisplayDelegate = nil; - self.adView.adEventDelegate = nil; -} - -#pragma mark - Ad Load Delegate - -- (void)adService:(ALAdService *)adService didLoadAd:(ALAd *)ad -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)adService:(ALAdService *)adService didFailToLoadAdWithError:(int)code -{ - // Look at ALErrorCodes.h for list of error codes - [self logCallback: __PRETTY_FUNCTION__]; -} - -#pragma mark - Ad Display Delegate - -- (void)ad:(ALAd *)ad wasDisplayedIn:(UIView *)view -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad wasHiddenIn:(UIView *)view -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad wasClickedIn:(UIView *)view -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -#pragma mark - Ad View Event Delegate - -- (void)ad:(ALAd *)ad didPresentFullscreenForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad willDismissFullscreenForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad didDismissFullscreenForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad willLeaveApplicationForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad didFailToDisplayInAdView:(ALAdView *)adView withError:(ALAdViewDisplayErrorCode)code -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.h deleted file mode 100644 index 1eb979fed0..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// ALDemoProgrammaticMRECViewController.h -// iOS-SDK-Demo-ObjC -// -// Created by Thomas So on 3/6/17. -// Copyright © 2017 AppLovin. All rights reserved. -// - -#import "ALBaseAdViewController.h" - -@interface ALDemoProgrammaticMRECViewController : ALBaseAdViewController - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.m deleted file mode 100644 index b7d0b0adaf..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/MRECs/Programmatic/ALDemoProgrammaticMRECViewController.m +++ /dev/null @@ -1,166 +0,0 @@ -// -// ALDemoProgrammaticMRECViewController.m -// iOS-SDK-Demo-ObjC -// -// Created by Thomas So on 3/6/17. -// Copyright © 2017 AppLovin. All rights reserved. -// - -#import "ALDemoProgrammaticMRECViewController.h" -#import - -@interface ALDemoProgrammaticMRECViewController() -@property (nonatomic, strong) ALAdView *adView; -@end - -@implementation ALDemoProgrammaticMRECViewController -static const CGFloat kMRECHeight = 250.0f; -static const CGFloat kMRECWidth = 300.0f; - -#pragma mark - View Lifecycle - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear: animated]; - - // Create the MREC view - self.adView = [[ALAdView alloc] initWithSize: ALAdSize.mrec]; - - // Optional: Implement the ad delegates to receive ad events. - self.adView.adLoadDelegate = self; - self.adView.adDisplayDelegate = self; - self.adView.adEventDelegate = self; - self.adView.translatesAutoresizingMaskIntoConstraints = false; - self.callbackTableView.translatesAutoresizingMaskIntoConstraints = false; - - // Call loadNextAd() to start showing ads - [self.adView loadNextAd]; - - [self.view addSubview: self.adView]; - - [self.view addConstraints: @[ - [NSLayoutConstraint constraintWithItem: self.callbackTableView - attribute: NSLayoutAttributeTop - relatedBy: NSLayoutRelationEqual - toItem: self.view - attribute: NSLayoutAttributeTop - multiplier: 1.0 - constant: 0], - [NSLayoutConstraint constraintWithItem: self.callbackTableView - attribute: NSLayoutAttributeLeading - relatedBy: NSLayoutRelationEqual - toItem: self.view - attribute: NSLayoutAttributeLeading - multiplier: 1.0 - constant: 0], - [NSLayoutConstraint constraintWithItem: self.callbackTableView - attribute: NSLayoutAttributeTrailing - relatedBy: NSLayoutRelationEqual - toItem: self.view - attribute: NSLayoutAttributeTrailing - multiplier: 1.0 - constant: 0], - [NSLayoutConstraint constraintWithItem: self.adView - attribute: NSLayoutAttributeCenterX - relatedBy: NSLayoutRelationEqual - toItem: self.view - attribute: NSLayoutAttributeCenterX - multiplier: 1.0 - constant: 0.0], - [NSLayoutConstraint constraintWithItem: self.adView - attribute: NSLayoutAttributeTop - relatedBy: NSLayoutRelationEqual - toItem: self.callbackTableView - attribute: NSLayoutAttributeBottom - multiplier: 1.0 - constant: 10.0], - [NSLayoutConstraint constraintWithItem: self.view - attribute: NSLayoutAttributeBottom - relatedBy: NSLayoutRelationEqual - toItem: self.adView - attribute: NSLayoutAttributeBottom - multiplier: 1.0 - constant: 10], - [NSLayoutConstraint constraintWithItem: self.adView - attribute: NSLayoutAttributeHeight - relatedBy: NSLayoutRelationEqual - toItem: nil - attribute: NSLayoutAttributeNotAnAttribute - multiplier: 1.0 - constant: kMRECHeight], - [NSLayoutConstraint constraintWithItem: self.adView - attribute: NSLayoutAttributeWidth - relatedBy: NSLayoutRelationEqual - toItem: nil - attribute: NSLayoutAttributeNotAnAttribute - multiplier: 1.0 - constant: kMRECWidth]]]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear: animated]; - - self.adView.adLoadDelegate = nil; - self.adView.adDisplayDelegate = nil; - self.adView.adEventDelegate = nil; -} - -#pragma mark - Ad Load Delegate - -- (void)adService:(ALAdService *)adService didLoadAd:(ALAd *)ad -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)adService:(ALAdService *)adService didFailToLoadAdWithError:(int)code -{ - // Look at ALErrorCodes.h for list of error codes - [self logCallback: __PRETTY_FUNCTION__]; -} - -#pragma mark - Ad Display Delegate - -- (void)ad:(ALAd *)ad wasDisplayedIn:(UIView *)view -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad wasHiddenIn:(UIView *)view -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad wasClickedIn:(UIView *)view -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -#pragma mark - Ad View Event Delegate - -- (void)ad:(ALAd *)ad didPresentFullscreenForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad willDismissFullscreenForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad didDismissFullscreenForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad willLeaveApplicationForAdView:(ALAdView *)adView -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)ad:(ALAd *)ad didFailToDisplayInAdView:(ALAdView *)adView withError:(ALAdViewDisplayErrorCode)code -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.h deleted file mode 100644 index a51abfcfdd..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// ALDemoNativeAdFeedTableViewController.h -// iOS-SDK-Demo -// -// Created by Thomas So on 9/24/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import - -@interface ALDemoNativeAdFeedTableViewController : UITableViewController - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.m deleted file mode 100644 index df23aed98d..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/ALDemoNativeAdFeedTableViewController.m +++ /dev/null @@ -1,98 +0,0 @@ -// -// ALDemoNativeAdFeedTableViewController.m -// iOS-SDK-Demo -// -// Created by Thomas So on 9/24/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALDemoNativeAdFeedTableViewController.h" -#import "ALCarouselView.h" -#import "ALDemoRSSFeedRetriever.h" - -// -// This view controller demonstrates how to display native ads using our open-source carousel views. -// - -@interface ALDemoNativeAdFeedTableViewController() -@property (nonatomic, strong) NSArray *articles; -@end - -@implementation ALDemoNativeAdFeedTableViewController -static NSString *const kArticleCellIdentifier = @"articleCell"; -static NSString *const kAdCellIdentifier = @"adCell"; - -static NSUInteger const kCellTagTitleLabel = 2; -static NSUInteger const kCellTagSubtitleLabel = 3; -static NSUInteger const kCellTagDescriptionLabel = 4; - -#pragma mark - View Lifecycle - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - [[ALDemoRSSFeedRetriever sharedRetriever] startParsingWithCompletion:^(NSError * _Nullable error, NSArray * _Nonnull articles) { - dispatch_async(dispatch_get_main_queue(), ^{ - - if ( error || articles.count == 0 ) - { - UIAlertController *alert = [UIAlertController alertControllerWithTitle: @"ERROR" message: error.localizedDescription preferredStyle: UIAlertControllerStyleAlert]; - [alert addAction: [UIAlertAction actionWithTitle: @"OK" style: UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { - [self.navigationController popViewControllerAnimated: YES]; - }]]; - [self presentViewController: alert animated: YES completion: nil]; - } - else - { - self.articles = articles; - [self.tableView reloadData]; - } - }); - }]; -} - -#pragma mark - Table View Data Source - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - return self.articles.count; -} - -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath -{ - return self.articles[indexPath.row].isAd ? 360.0f : 280.0f; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - UITableViewCell *cell; - ALDemoArticle *article = self.articles[indexPath.row]; - - if ( article.isAd ) - { - // You can configure carousels in ALCarouselViewSettings.h - cell = [tableView dequeueReusableCellWithIdentifier: kAdCellIdentifier forIndexPath:indexPath]; - } - else - { - cell = [tableView dequeueReusableCellWithIdentifier: kArticleCellIdentifier forIndexPath:indexPath]; - ((UILabel *)[cell viewWithTag: kCellTagTitleLabel]).text = article.title; - ((UILabel *)[cell viewWithTag: kCellTagSubtitleLabel]).text = [NSString stringWithFormat: @"%@ - %@", article.creator, article.pubDate]; - ((UILabel *)[cell viewWithTag: kCellTagDescriptionLabel]).text = article.articleDescription; - } - - return cell; -} - -#pragma mark - Table View Delegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - [tableView deselectRowAtIndexPath: indexPath animated: YES]; - - ALDemoArticle *article = self.articles[indexPath.row]; - [[UIApplication sharedApplication] openURL: article.link]; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.h deleted file mode 100644 index 3c6061c88e..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// ALCarouselCardState.h -// sdk -// -// Created by Matt Szaro on 4/17/15. -// -// - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * Tracks the state of a card within an ALCarouselView. - */ -@interface ALCarouselCardState : NSObject - -/** - Retrieve an instance with appropriate default settings for use within a carousel view. - */ -+(instancetype) cardStateForCarousel; - -/** - Retrieve an instance with appropriate default settings for use within a single ALCarouselCardView outside a carousel. - */ -+(instancetype) cardStateForSingleCard; - -typedef NS_ENUM(NSUInteger, ALMuteState) -{ - ALMuteStateUnspecified, - ALMuteStateUnmuted, - ALMuteStateMuted -}; - -@property (assign, atomic, getter=wasVideoStarted) BOOL videoStarted; -@property (assign, atomic, getter=wasVideoCompleted) BOOL videoCompleted; -@property (assign, atomic, getter=wasVideoStartTracked) BOOL videoStartTracked; -@property (assign, atomic, getter=isFirstPlayback) BOOL firstPlayback; -@property (assign, atomic, getter=wasImpressionTracked) BOOL impressionTracked; -@property (assign, atomic, getter=isCurrentlyActive) BOOL currentlyActive; -@property (assign, atomic, getter=isReplayOverlayVisible) BOOL replayOverlayVisible; -@property (assign, atomic, getter=isPrecaching) BOOL precaching; // To prvent a slot from being redundantly pre-caching - -@property (assign, atomic) Float64 lastMediaPlayerPosition; -@property (assign, atomic) ALMuteState muteState; -@property (strong, atomic) UIImage *screenshot; -@property (assign, atomic) CGRect videoRect; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.m deleted file mode 100644 index d8350f8831..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselCardState.m +++ /dev/null @@ -1,34 +0,0 @@ -// -// ALCarouselCardState.m -// sdk -// -// Created by Matt Szaro on 4/17/15. -// -// - -#import "ALCarouselCardState.h" - -@implementation ALCarouselCardState - -+(instancetype) cardStateForCarousel -{ - ALCarouselCardState* state = [[[self class] alloc] init]; - - state.muteState = ALMuteStateUnspecified; - state.firstPlayback = YES; - - return state; -} - -+(instancetype) cardStateForSingleCard -{ - ALCarouselCardState* state = [[[self class] alloc] init]; - - state.muteState = ALMuteStateUnspecified; - state.currentlyActive = YES; - state.firstPlayback = YES; - - return state; -} - -@end \ No newline at end of file diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselRenderingProtocol.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselRenderingProtocol.h deleted file mode 100644 index 30454997ed..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselRenderingProtocol.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// ALCarouselRenderingProtocol.h -// sdk -// -// Created by Matt Szaro on 5/7/15. -// -// - -@import AppLovinSDK; -#import -#import "ALCarouselCardState.h" - -@protocol ALCarouselRenderingProtocol - -@optional -- (void)renderViewForNativeAd:(ALNativeAd *)ad; - -@required -- (void)renderViewForNativeAd:(ALNativeAd *)ad cardState:(ALCarouselCardState *)cardState; - -/** - * Resets the current card's view properties. - */ -- (void)clearView; - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.h deleted file mode 100644 index 4c51732b59..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// ALCarouselModel.h -// sdk -// -// Created by Matt Szaro on 4/20/15. -// -// - -#import -#import - -@class ALNativeAd; -@class ALCarouselCardState; -@class ALSdk; - -NS_ASSUME_NONNULL_BEGIN - -@interface ALCarouselViewModel : NSObject - -@property (strong, nonatomic, readonly) NSArray *nativeAds; -@property (assign, nonatomic, readonly) NSUInteger nativeAdsCount; - -- (instancetype)initWithNativeAds:(NSArray *)ads; -- (nullable ALCarouselCardState *)cardStateForNativeAd:(ALNativeAd *)ad; -- (nullable ALCarouselCardState *)cardStateAtNativeAdIndex:(NSUInteger)index; -- (nullable ALNativeAd *)nativeAdAtIndex:(NSUInteger)index; - -- (void)removeAllObjects; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.m deleted file mode 100644 index e22b46d780..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALCarouselViewModel.m +++ /dev/null @@ -1,174 +0,0 @@ -// -// ALCarouselModel.m -// sdk -// -// Created by Matt Szaro on 4/20/15. -// -// - -#import "ALCarouselViewModel.h" -#import "ALCarouselCardState.h" - -@interface ALCarouselViewModel () - -@property (strong, nonatomic) ALSdk* sdk; - -@property (strong, nonatomic) NSArray* nativeAds; -@property (strong, nonatomic) NSMutableDictionary* cardStates; - -@end - -@implementation ALCarouselViewModel -@dynamic nativeAdsCount; - -static void* ALCarouselViewModelKVOContext = &ALCarouselViewModelKVOContext; -static NSString* kKeypathMuteState = @"muteState"; - --(instancetype) initWithNativeAds: (NSArray *)ads -{ - self = [super init]; - if ( self ) - { - self.nativeAds = ads; - self.cardStates = [NSMutableDictionary dictionary]; - } - return self; -} - -- (ALCarouselCardState *)cardStateAtNativeAdIndex:(NSUInteger)index -{ - if ( index >= [self nativeAdsCount]) - { - NSLog(@"Requested card state at native ad index %lu is out-of-bounds", index); - return nil; - } - else - { - ALCarouselCardState* cardState = self.cardStates[ @(index) ]; - if ( cardState ) - { - NSLog(@"Requested card state at native ad index %lu", index); - return cardState; - } - else - { - NSLog(@"Requested card state at native ad index %lu does not exist yet. Creating new card state", index); - - ALCarouselCardState* newState = [ALCarouselCardState cardStateForCarousel]; - [self beginObservingCardState: newState]; - [self.cardStates setObject: newState forKey: @(index)]; - - return newState; - } - } -} - --(void) beginObservingCardState: (ALCarouselCardState*) cardState -{ - // Observe any properties which need to be synchronized among all card states. - // E.g., propogate mute settings among cards while within a carousel view. - // This allows us to add syncronization features on top of the card state without adding complexity for single card integrations. - - [cardState addObserver: self - forKeyPath: kKeypathMuteState - options: NSKeyValueObservingOptionNew - context: ALCarouselViewModelKVOContext]; -} - --(void) endObservingCardState: (ALCarouselCardState*) cardState -{ - // Observe any properties which need to be synchronized among all card states. - // E.g., propogate mute settings among cards while within a carousel view. - // This allows us to add syncronization features on top of the card state without adding complexity for single card integrations. - - @try { - [cardState removeObserver: self - forKeyPath: kKeypathMuteState - context: ALCarouselViewModelKVOContext]; - } - @catch (NSException* __unused ignore) - { - } -} - --(void) observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context -{ - if (context == ALCarouselViewModelKVOContext) - { - if ([keyPath isEqual: kKeypathMuteState]) - { - NSNumber* newValue = change[NSKeyValueChangeNewKey]; - ALMuteState muteState = (ALMuteState) [newValue unsignedIntegerValue]; - - if (muteState != ALMuteStateUnspecified) - { - [self updateMuteStates: muteState]; - } - } - } - else - { - [super observeValueForKeyPath: keyPath ofObject: object change: change context: context]; - } -} - --(void) updateMuteStates: (ALMuteState) newState -{ - [self.cardStates enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - ALCarouselCardState* cardState = (ALCarouselCardState*) obj; - [self endObservingCardState: cardState]; - cardState.muteState = newState; - [self beginObservingCardState: cardState]; - }]; -} - -- (ALCarouselCardState *)cardStateForNativeAd:(ALNativeAd *)ad -{ - NSUInteger index = [self.nativeAds indexOfObject: ad]; - if ( index != NSNotFound ) - { - return [self cardStateAtNativeAdIndex: index]; - } - else - { - return nil; - } -} - -- (ALNativeAd *)nativeAdAtIndex:(NSUInteger)index -{ - if ( index < self.nativeAds.count ) - { - NSLog(@"Requested native ad index %lu", index); - return [self.nativeAds objectAtIndex: index]; - } - else - { - NSLog(@"Requested native ad index %lu is out of bounds", index); - return nil; - } -} - -- (NSUInteger)nativeAdsCount -{ - return self.nativeAds.count; -} - --(void) removeAllObjects; -{ - self.nativeAds = nil; - - [self.cardStates enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - ALCarouselCardState* cardState = (ALCarouselCardState*) obj; - [self endObservingCardState: cardState]; - }]; - - [self.cardStates removeAllObjects]; -} - --(void) dealloc -{ - [self removeAllObjects]; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.h deleted file mode 100644 index c48d014873..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// ALVideoPlayer.h -// sdk -// -// Created by Matt Szaro on 6/23/14. -// -// - -@import AppLovinSDK; -@import AVFoundation; -@import CoreMedia; -#import "ALNativeAdVideoView.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ALNativeAdVideoPlayer : NSObject - -@property (strong, nonatomic, readonly) ALNativeAdVideoView* videoView; -@property (strong, nonatomic, readonly) AVPlayerItem* playerItem; -@property (strong, nonatomic, readonly) AVAsset* playerAsset; -@property (strong, nonatomic, readwrite) NSURL* mediaSource; - --(instancetype) initWithMediaSource: (nullable NSURL*) aMediaSource; - --(void) playVideo; --(void) stopVideo; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.m deleted file mode 100644 index c52389bc76..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/ALNativeAdVideoPlayer.m +++ /dev/null @@ -1,67 +0,0 @@ -// -// ALVideoPlayer.m -// sdk -// -// Created by Matt Szaro on 6/23/14. -// -// - -#import "ALNativeAdVideoPlayer.h" - -@interface ALNativeAdVideoPlayer() - -@property (strong, nonatomic, readwrite) ALNativeAdVideoView* videoView; -@property (strong, nonatomic, readwrite) AVPlayerItem* playerItem; -@property (strong, nonatomic, readwrite) AVAsset* playerAsset; -@property (strong, nonatomic, readwrite) AVPlayer* player; - -@end - -@implementation ALNativeAdVideoPlayer - --(instancetype) initWithMediaSource:(NSURL *)aMediaSource -{ - self = [super init]; - if(self) - { - self.mediaSource = aMediaSource; - self.videoView = [self createVideoView]; - } - return self; -} - --(ALNativeAdVideoView*) createVideoView -{ - self.playerAsset = [AVAsset assetWithURL: self.mediaSource]; - self.playerItem = [AVPlayerItem playerItemWithAsset: self.playerAsset]; - self.player = [AVPlayer playerWithPlayerItem: self.playerItem]; - - ALNativeAdVideoView* videoView = [[ALNativeAdVideoView alloc] initWithPlayer: self.player]; - videoView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect; - - return videoView; -} - --(void) playVideo -{ - [self.videoView.player play]; -} - --(void) stopVideo -{ - [self.videoView.player pause]; -} - --(void) setMediaSource:(NSURL *)mediaSource -{ - if (![_mediaSource isEqual: mediaSource]) { - - _mediaSource = mediaSource; - - self.playerAsset = [AVAsset assetWithURL: self.mediaSource]; - self.playerItem = [AVPlayerItem playerItemWithAsset: self.playerAsset]; - - [self.player replaceCurrentItemWithPlayerItem: self.playerItem]; - } -} -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_0.5.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_0.5.png deleted file mode 100644 index 2e0f5341136a11ec50e5b5521e1dcb5ae0f20bb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3806 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 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_0.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_0.png deleted file mode 100644 index 9283ab8508ffa14fe7cda1f439268ada3c714271..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3797 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 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_1.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_1.png deleted file mode 100644 index e14864d3cc55b5dd3485856bb71b032d8ce24829..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3738 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 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_3.5.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_3.5.png deleted file mode 100644 index b96d07a0534cc80dab0cb9b37479244b4f0fca6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3810 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 AX8-^I diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_3.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_3.png deleted file mode 100644 index 7ff58caeec1bf31eaee58e321edf5a2f37fe6ca9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3808 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 D?_8?D diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_4.5.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_4.5.png deleted file mode 100644 index 8023c19deeeed82610f1fcca4144bc4d0f9c7368..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3749 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 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_5.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/Star_Sprite_5.png deleted file mode 100644 index ad40f083079246df9d1c7822ef2b7444b67e7387..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3849 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 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_learn_more.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_learn_more.png deleted file mode 100644 index 21b8472308809bf8e881e6c8ae90ab14e36f2b9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11806 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 k!GXc@q+qV)8;AN&;02><{9 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_play.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_play.png deleted file mode 100644 index 2acb854f1827a12957418f1e22aa868459f37d2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10380 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 KtXZ!Pi}^narUn53 diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_replay.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_replay.png deleted file mode 100644 index 2ed3bd3bfef802b7e2c14abd2c16186ae5f67744..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15399 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 ZmADu$o@n+~T)(=jEUzy2?xAVe{{yXJ(ii{$ diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_unmuted.png b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Assets/applovin_card_unmuted.png deleted file mode 100644 index 773cdb07fe2297e3cc7993e849795b1c80a44c4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5483 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 - -NS_ASSUME_NONNULL_BEGIN - -@interface UIView (ALActivityIndicator) - -/** - * Show an activity indicator with a semi-transparent black overlay underneath without fade. - */ -- (void)al_showActivityIndicator; - -/** - * Show an activity indicator with a semi-transparent black overlay underneath with a fade animation option. - */ -- (void)al_showActivityIndicatorAnimated:(BOOL)animated; - -/** - * Hides the activity indicator view without fade. - */ -- (void)al_hideActivityIndicator; - -/** - * Hides the activity indicator view with a fade animation option. - */ -- (void)al_hideActivityIndicatorAnimated:(BOOL)animated; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Categories/UIView+ALActivityIndicator.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Categories/UIView+ALActivityIndicator.m deleted file mode 100644 index 92e3121a1a..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Categories/UIView+ALActivityIndicator.m +++ /dev/null @@ -1,87 +0,0 @@ -// -// UIView+ALActivityIndicator.m -// sdk -// -// Created by Thomas So on 5/15/15. -// -// - -#import "UIView+ALActivityIndicator.h" -#import "ALCarouselView+Internal.h" - -@implementation UIView(ALActivityIndicator) -static NSString *const kActivityIndicatorKey = @"activityIndicator"; -static NSString *const kActivityIndicatorOverlayKey = @"activityIndicatorOverlay"; - -static const CGFloat kTargetOverlayAlpha = 1.0f; -static const CGFloat kAnimationDuration = 0.35f; - -- (void)al_showActivityIndicator -{ - [self al_showActivityIndicatorAnimated: NO]; -} - -- (void)al_showActivityIndicatorAnimated:(BOOL)animated -{ - UIView *overlay = [self valueForKey: kActivityIndicatorOverlayKey]; - if ( !overlay ) - { - overlay = [[UIView alloc] init]; - overlay.backgroundColor = [UIColor whiteColor]; - overlay.frame = self.bounds; - - NSLog(@"Created overlay with frame: %@", NSStringFromCGRect(overlay.frame)); - - [self setValue: overlay forKey: kActivityIndicatorOverlayKey]; - } - - UIActivityIndicatorView *activityIndicator = [self valueForKey: kActivityIndicatorKey]; - if ( !activityIndicator ) - { - activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray]; - activityIndicator.hidesWhenStopped = YES; - activityIndicator.center = self.center; - - [overlay addSubview: activityIndicator]; - [overlay bringSubviewToFront: activityIndicator]; - - [self setValue: activityIndicator forKey: kActivityIndicatorKey]; - } - - [activityIndicator startAnimating]; - overlay.alpha = animated ? 0.0f : kTargetOverlayAlpha; - - [self addSubview: overlay]; - [self bringSubviewToFront: overlay]; - - if ( animated ) - { - [UIView animateWithDuration: kAnimationDuration animations:^{ - overlay.alpha = kTargetOverlayAlpha; - }]; - } -} - -- (void)al_hideActivityIndicator -{ - [self al_hideActivityIndicatorAnimated: NO]; -} - -- (void)al_hideActivityIndicatorAnimated:(BOOL)animated -{ - UIView *overlay = [self valueForKey: kActivityIndicatorOverlayKey]; - if ( !overlay.superview ) - { - return; - } - - UIActivityIndicatorView *activityIndicator = [self valueForKey: kActivityIndicatorKey]; - [UIView animateWithDuration: animated ? kAnimationDuration : 0.0f animations:^{ - overlay.alpha = 0.0f; - } completion:^(BOOL finished) { - [activityIndicator stopAnimating]; - [overlay removeFromSuperview]; - }]; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h deleted file mode 100644 index 84cad4d4fd..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h +++ /dev/null @@ -1,86 +0,0 @@ -// -// ALCarouselViewSettings.h -// iOS Test App NG -// -// Created by Thomas So on 5/27/15. -// Copyright (c) 2015 AppLovin. All rights reserved. -// - -/** - * This file contains advanced UI configuration for ALCarouselView. - * Sizing and colors can be easily tweaked to your liking here. - */ - -#ifndef iOS_Test_App_NG_ALCarouselViewSettings_h -#define iOS_Test_App_NG_ALCarouselViewSettings_h - -#define kTextColor [UIColor darkTextColor] -#define kReplayTextColor [UIColor whiteColor] -#define kCarouselBackgroundColor [UIColor whiteColor] -#define kCardBackgroundColor [UIColor whiteColor] -#define kCardButtonColor [UIColor colorWithWhite: 0.84f alpha: 1.0f] -#define kVideoViewBackgroundColor [UIColor blackColor] -#define kVideoViewBackgroundWhilePlayingColor [UIColor blackColor] -#define kReplayOverlayBackgroundColor [UIColor blackColor] -#define kButtonHighlightTint [UIColor colorWithWhite: 0.87f alpha: 1.0f] - -// Media controls -static BOOL const kIsAutoplay = YES; -static BOOL const kVideoClicksThrough = YES; -static BOOL const kConfigIsMuted = YES; -static BOOL const kRenderVideoScreenshotAsFallbackImage = YES; - -// Replay overlay controls -static NSString *const kTextReplayVideo = @"Replay Video"; -static NSString *const kTextLearnMore = @"Learn More"; -static CGFloat const kConfigReplayOverlayAlpha = 0.75f; - - - -// Carousel constants -static NSUInteger const kNativeAdsToLoadCount = 3; -static NSString *const kFontFamily = @""; - -// Carousel layout constants -static CGFloat const kCardWidthPercentage = 0.90f; // As percentage of width of screen -static CGFloat const kCardMargin = 5.0f; // The margin on the side of each card. So a margin of 5px would result in a total of 10px separation card-to-card - -// Spring animation constants -static CGFloat const kSpringDuration = 0.3f; -static CGFloat const kDelay = 0.0f; -static CGFloat const kSpringDampeningGoNextCard = 0.9f; -static CGFloat const kSpringDampeningReturnSameCard = 0.7f; -static CGFloat const kInitialSpringVelocity = 0.0f; -static CGFloat const kConfigSwipeThreshold = 40.0f; // The number of pixels that will trigger a swipe event - -// Card layout constants -static CGFloat const kCardPadding = 10.0f; -static CGFloat const kTopMargin = 5.0f; -static CGFloat const kAppIconSize = 40.0f; -static CGFloat const kRatingHeight = 15.0f; -static CGFloat const kStarRatingTopPadding = 0.0f; -static CGFloat const kMaxStarRatingHeight = 15.0f; -static NSUInteger const kStarWidthToHeightMultiplier = 5; -static CGFloat const kDescriptionVerticalMargin = 16.0f; -static CGFloat const kVideoAspectRatio = 1.0f/1.78f; -static CGFloat const kDescriptionTextHeight = 36.0f; -static CGFloat const kCtaMaxHeight = 40.0f; -static CGFloat const kCtaCornerRadius = 3.0f; - -// Card configurations -static BOOL const kConfigEntireCardClickable = YES; -static CGFloat const kFontSizeTitle = 14.0f; -static CGFloat const kFontSizeDescription = 14.0f; -static CGFloat const kFontSizeButton = 18.0f; -static NSUInteger const kDescriptionMaxLines = 2; - -// Media layout constants -static CGFloat const kPadding = 10.0f; -static CGFloat const kMuteButtonPadding = 12.0f; -static CGFloat const kMuteWidth = 20.0f; -static CGFloat const kMuteHeight = 20.0f; -static CGFloat const kMuteButtonMargin = 8.0f; -static CGFloat const kPlayReplayWidth = 40.0f; -static CGFloat const kPlayReplayHeight = 40.0f; - -#endif \ No newline at end of file diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.h deleted file mode 100644 index 399ed62aea..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// ALCarouselCardView.h -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -#import - -#import "ALCarouselMediaView.h" -#import "ALCarouselViewModel.h" -#import "ALCarouselRenderingProtocol.h" - -NS_ASSUME_NONNULL_BEGIN - -@class ALCarouselView; - -/** - * This view is used for paging of the carousel. - */ -@interface ALCarouselCardView : UIView - -/** - * The view containing the ad video or image. - */ -@property (strong, nonatomic) ALCarouselMediaView *mediaView; - -/** - * Initializes a newly allocated card view object with the specified sdk - */ -- (instancetype) initWithSdk:(ALSdk *)sdk; - -/** - * Redirects to the CTA for the given ad. - * - * @param ad The ad with the CTA URL to redirect to. - */ -- (void)handleClickForAd:(ALNativeAd *)ad; - -/** - Call this method when your view is displayed to the user. - Will track an impression. - */ -- (void)trackImpression; - -@property (strong, nonatomic, nullable) UIActivityIndicatorView *activityIndicator; -@property (strong, nonatomic, nullable) UIView *activityIndicatorOverlay; - -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.m deleted file mode 100644 index 1e278814e3..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselCardView.m +++ /dev/null @@ -1,353 +0,0 @@ -// -// ALCarouselCardView.m -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -@import AppLovinSDK; -#import "ALCarouselCardView.h" -#import "ALCarouselCardState.h" -#import "UIView+ALActivityIndicator.h" -#import "ALCarouselViewSettings.h" - -@interface ALCarouselCardView() - -@property (weak, nonatomic) ALSdk *sdk; - -@property (strong, nonatomic) ALCarouselCardState *cardState; -@property (strong, nonatomic) ALNativeAd *ad; - -@property (strong, nonatomic) UITapGestureRecognizer *cardTapGesture; -@property (strong, nonatomic) UIView *contentView; -@property (strong, nonatomic) UIView *topBarContainer; -@property (strong, nonatomic) UIImageView *appIcon; -@property (strong, nonatomic) UILabel *titleLabel; -@property (strong, nonatomic) UIImageView *ratingImageView; -@property (strong, nonatomic) UILabel *descriptionLabel; -@property (strong, nonatomic) UIButton *ctaButton; - -@end - -@implementation ALCarouselCardView -static NSString *const TAG = @"ALCarouselCardView"; - -#pragma mark - Initialization - -- (instancetype)initWithSdk:(ALSdk *)sdk -{ - self = [super init]; - if ( self ) - { - [self baseInitWithSdk: sdk]; - } - return self; -} - -- (instancetype)initWithFrame: (CGRect) frame -{ - self = [super initWithFrame: frame]; - if ( self ) - { - [self baseInitWithSdk: [ALSdk shared]]; - } - return self; -} - -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder: aDecoder]; - if ( self ) - { - [self baseInitWithSdk: [ALSdk shared]]; - } - return self; -} - -- (void)baseInitWithSdk:(ALSdk*) sdk -{ - self.sdk = sdk; - - self.backgroundColor = [UIColor clearColor]; - - self.cardTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapCard:)]; - self.cardTapGesture.enabled = kConfigEntireCardClickable; - [self addGestureRecognizer: self.cardTapGesture]; - - self.contentView = [[UIView alloc] init]; - self.contentView.backgroundColor = kCardBackgroundColor; - [self addSubview: self.contentView]; - - self.topBarContainer = [[UIView alloc] init]; - [self.contentView addSubview: self.topBarContainer]; - - self.appIcon = [[UIImageView alloc] init]; - self.appIcon.userInteractionEnabled = YES; - [self.contentView addSubview: self.appIcon]; - - UITapGestureRecognizer *appIconTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapAppIcon:)]; - [self.appIcon addGestureRecognizer: appIconTapGesture]; - - self.titleLabel = [[UILabel alloc] init]; - self.titleLabel.textColor = kTextColor; - [self.topBarContainer addSubview: self.titleLabel]; - - self.ratingImageView = [[UIImageView alloc] init]; - self.ratingImageView.contentMode = UIViewContentModeScaleAspectFit; - [self.topBarContainer addSubview: self.ratingImageView]; - - self.descriptionLabel = [[UILabel alloc] init]; - self.descriptionLabel.textColor = kTextColor; - self.descriptionLabel.numberOfLines = kDescriptionMaxLines; - [self.contentView addSubview: self.descriptionLabel]; - - self.mediaView = [[ALCarouselMediaView alloc] initWithSdk: self.sdk parentView: self]; - [self.contentView addSubview: self.mediaView]; - - self.ctaButton = [[UIButton alloc] init]; - self.ctaButton.layer.masksToBounds = YES; - self.ctaButton.layer.cornerRadius = kCtaCornerRadius; - self.ctaButton.backgroundColor = kCardButtonColor; - [self.ctaButton setTitleColor: kTextColor forState: UIControlStateNormal]; - [self.ctaButton addTarget: self action: @selector(didTapCTAButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.contentView addSubview: self.ctaButton]; - - // Determine label fonts - if ( [[UIFont familyNames] containsObject: kFontFamily] ) - { - self.titleLabel.font = [UIFont fontWithName: kFontFamily size: kFontSizeTitle]; - self.descriptionLabel.font = [UIFont fontWithName: kFontFamily size: kFontSizeDescription]; - self.ctaButton.titleLabel.font = [UIFont fontWithName: kFontFamily size: kFontSizeButton]; - } - else - { - self.titleLabel.font = [UIFont systemFontOfSize: kFontSizeTitle]; - self.descriptionLabel.font = [UIFont systemFontOfSize: kFontSizeDescription]; - self.ctaButton.titleLabel.font = [UIFont systemFontOfSize: kFontSizeButton]; - } -} - -#pragma mark - Action Methods - -- (void)didTapCTAButton:(UIButton *)sender -{ - NSLog(@"Redirecting from cta button click"); - [self handleClickForAd: self.ad]; -} - -- (void)didTapAppIcon:(UITapGestureRecognizer *)tapGesture -{ - NSLog(@"Redirecting from app icon click"); - [self handleClickForAd: self.ad]; -} - -- (void)didTapCard:(UITapGestureRecognizer *)tapGesture -{ - NSLog(@"Redirecting from card click"); - [self handleClickForAd: self.ad]; -} - -#pragma mark - View Management - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - // Layout content view - CGRect contentFrame = CGRectZero; - contentFrame.origin.x = kCardMargin; - contentFrame.size.width = CGRectGetWidth(self.bounds) - (2*kCardMargin); - contentFrame.size.height = CGRectGetHeight(self.bounds); - self.contentView.frame = contentFrame; - - // Layout app icon - self.appIcon.frame = CGRectMake(kCardPadding, kTopMargin, kAppIconSize, kAppIconSize); - - // Layout title - CGRect titleFrame = CGRectZero; - titleFrame.size.width = (CGRectGetWidth(self.contentView.frame) - CGRectGetMaxX(self.appIcon.frame)) - (2*kCardPadding); - titleFrame.size.height = [self.titleLabel sizeThatFits: CGSizeMake(CGRectGetWidth(titleFrame), CGFLOAT_MAX)].height; - self.titleLabel.frame = titleFrame; - - // Layout star rating - const CGFloat ratingWidth = kMaxStarRatingHeight*kStarWidthToHeightMultiplier; - self.ratingImageView.frame = CGRectMake(CGRectGetMinX(titleFrame), CGRectGetMaxY(titleFrame) + kStarRatingTopPadding, ratingWidth, kRatingHeight); - - // Layout top bar - CGRect topBarFrame = CGRectZero; - topBarFrame.origin.x = CGRectGetMaxX(self.appIcon.frame) + kCardPadding; - topBarFrame.size.width = CGRectGetWidth(self.contentView.frame) - (3*kCardPadding) - kAppIconSize; - topBarFrame.size.height = CGRectGetHeight(self.titleLabel.frame) + kRatingHeight; - self.topBarContainer.frame = topBarFrame; - self.topBarContainer.center = CGPointMake(self.topBarContainer.center.x, self.appIcon.center.y); - - // Layout description - CGRect descriptionFrame = CGRectZero; - descriptionFrame.origin.x = kCardPadding; - descriptionFrame.origin.y = CGRectGetMaxY(self.topBarContainer.frame) + kDescriptionVerticalMargin; - descriptionFrame.size.width = CGRectGetWidth(self.contentView.frame) - (2*kCardPadding); - descriptionFrame.size.height = [self.descriptionLabel sizeThatFits: CGSizeMake(CGRectGetWidth(descriptionFrame), CGFLOAT_MAX)].height; - self.descriptionLabel.frame = descriptionFrame; - - // Layout media view - const CGFloat maxHeightPossible = (CGRectGetMaxY(self.frame) - kCardPadding) - (CGRectGetMaxY(self.descriptionLabel.frame) + kCardPadding); - const CGFloat fittedHeight = (CGRectGetWidth(self.frame)) * kVideoAspectRatio; - - CGRect mediaFrame = CGRectZero; - mediaFrame.origin.y = CGRectGetMaxY(self.topBarContainer.frame) + (2*kDescriptionVerticalMargin) + kDescriptionTextHeight; - mediaFrame.size.width = CGRectGetWidth(self.contentView.frame); - mediaFrame.size.height = MIN(maxHeightPossible, fittedHeight); - self.mediaView.frame = mediaFrame; - - // Layout CTA button (center it between bottom of video and bottom of card) - const CGFloat ctaOriginY = CGRectGetMaxY(self.mediaView.frame) + (CGRectGetMaxY(self.contentView.frame) - CGRectGetMaxY(self.mediaView.frame))/2 - kCtaMaxHeight/2; - - // If button will overflow bottom, hide it - BOOL willOverflow = (ctaOriginY + kCtaMaxHeight) > CGRectGetMaxY(self.contentView.frame); - if ( willOverflow ) - { - self.ctaButton.frame = CGRectZero; - self.ctaButton.hidden = YES; - } - else - { - CGRect ctaFrame = CGRectZero; - ctaFrame.origin.y = ctaOriginY; - ctaFrame.size.height = kCtaMaxHeight; - ctaFrame.size.width = (2*kCardPadding) + [self.ctaButton sizeThatFits: CGSizeMake(CGFLOAT_MAX, 0.0f)].width; - ctaFrame.origin.x = CGRectGetWidth(self.contentView.frame) - kCardPadding - CGRectGetWidth(ctaFrame); - - self.ctaButton.frame = ctaFrame; - } - - // Activity Views from category - self.activityIndicatorOverlay.frame = self.bounds; - self.activityIndicator.center = self.activityIndicatorOverlay.center; -} - -#pragma mark - View Rendering - -- (void)renderViewForNativeAd:(ALNativeAd *)ad cardState:(ALCarouselCardState *)cardState -{ - if ( ad ) - { - self.ad = ad; - self.cardState = cardState; - - [self refresh]; - } - else - { - [self clearView]; - } -} - -- (void)refresh -{ - NSLog(@"----------Begin refreshing carousel card view----------"); - - ALNativeAd *ad = self.ad; - - // If there is ad, render - if ( ad ) - { - NSLog(@"Refreshing ad (%@) for card view", ad.adIdNumber); - - self.titleLabel.text = ad.title; - self.descriptionLabel.text = ad.descriptionText; - self.mediaView.hidden = NO; - self.ctaButton.hidden = NO; - [self.ctaButton setTitle: ad.ctaText forState: UIControlStateNormal]; - [self populateStarRating: ad]; - - // If the images are pre-cached, just render them - if ( [ad isImagePrecached] ) - { - NSLog(@"Native ad (%@) is pre-cached. Refreshing image resources", ad.adIdNumber); - -#pragma mark - Populate with appropriate stars asset depending on starRating - self.appIcon.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: ad.iconURL]]; // Local URL - - [self.mediaView renderViewForNativeAd: self.ad cardState: self.cardState]; - - [self al_hideActivityIndicatorAnimated: YES]; - [self setNeedsLayout]; - } - else - { - [self clearView]; - [self al_showActivityIndicator]; - } - } - // There is no slot to render, so clear view - else - { - NSLog(@"Refreshing nil native ad for card view. Clearing view..."); - - [self clearView]; - [self al_hideActivityIndicatorAnimated: YES]; - } - - NSLog(@"----------Finish refreshing carousel card view----------"); -} - -#pragma mark - Utility - -- (void)handleClickForAd:(ALNativeAd *)ad -{ - if ( ad ) - { - [ad launchClickTarget]; - } - else - { - // Something is wrong, trying to redirect when card view does not have a native ad (like when ad is still loading) - NSLog(@"Attempting to open CTA URL with a nil native ad"); - } -} - -- (void)trackImpression -{ - if ( self.ad && self.cardState ) - { - NSLog(@"Handling displaying of native ad (%@)", self.ad.adIdNumber); - - if ( !self.cardState.impressionTracked ) - { - self.cardState.impressionTracked = YES; - NSLog(@"Tracking impression for ad (%@)", self.ad.adIdNumber); - [self.ad trackImpression]; - } - } - else - { - NSLog(@"Attempting to handle a nil slot or nil card state being displayed"); - } -} - -- (void)populateStarRating:(ALNativeAd*) ad -{ - NSString* filename = [NSString stringWithFormat: @"Star_Sprite_%@", ad.starRating.stringValue]; - UIImage* starRating = [UIImage imageNamed: filename]; - self.ratingImageView.image = starRating; -} - -- (void)clearView -{ - self.titleLabel.text = @""; - self.descriptionLabel.text = @""; - self.ratingImageView.image = nil; - self.appIcon.image = nil; - - self.ctaButton.hidden = YES; - [self.ctaButton setTitle: @"" forState: UIControlStateNormal]; - - self.mediaView.hidden = YES; - - // Reset State - self.cardState = nil; - self.ad = nil; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.h deleted file mode 100644 index bfb300920e..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// ALCarouselMediaView.h -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -#import - -#import "ALCarouselViewModel.h" -#import "ALCarouselRenderingProtocol.h" - -@class ALCarouselCardView; - -NS_ASSUME_NONNULL_BEGIN - -/** - * This view is used to store the ad's media. - */ -@interface ALCarouselMediaView : UIView - -/** - * Saves the current video's states and clears it. This is for when moving a slot out of the middle card. - */ -- (void)setInactive; - -/** - * Initializes a newly allocated media view object with the specified sdk and parent card view. - */ -- (instancetype)initWithSdk:(ALSdk *)sdk parentView:(ALCarouselCardView *)parentView; -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.m deleted file mode 100644 index 8832a1d844..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselMediaView.m +++ /dev/null @@ -1,598 +0,0 @@ -// -// ALCarouselMediaView.m -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -@import AppLovinSDK; -#import "ALCarouselMediaView.h" -#import "ALCarouselCardState.h" -#import "ALCarouselReplayOverlayView.h" -#import "ALCarouselCardView.h" -#import "ALCarouselViewSettings.h" -#import "ALNativeAdVideoPlayer.h" -#import "ALNativeAdVideoView.h" - -@interface ALCarouselMediaView() - -@property (weak, nonatomic) ALSdk *sdk; - -@property (strong, nonatomic) ALCarouselCardView *cardView; -@property (strong, nonatomic) ALCarouselCardState *cardState; -@property (strong, nonatomic) ALNativeAd *ad; - -@property (strong, nonatomic) UIImageView *adImageView; - -@property (strong, nonatomic) ALNativeAdVideoPlayer *videoPlayer; -@property (weak, nonatomic) ALNativeAdVideoView *videoView; -@property (strong, nonatomic) UIButton *muteButton; -@property (strong, nonatomic) UIButton *playButton; -@property (strong, nonatomic) ALCarouselReplayOverlayView *replayOverlayView; - -@end - -@implementation ALCarouselMediaView -static NSString *const TAG = @"ALCarouselMediaView"; - -#pragma mark - Initialization Methods - -- (instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (self) - { - self.sdk = [ALSdk shared]; - [self setup]; - } - return self; -} - -- (instancetype)initWithSdk:(ALSdk *)sdk parentView:(ALCarouselCardView *)parentView; -{ - self = [super init]; - if ( self ) - { - self.sdk = sdk; - self.cardView = parentView; - [self setup]; - } - return self; -} - -- (void)setup -{ - self.backgroundColor = kVideoViewBackgroundColor; - - self.adImageView = [[UIImageView alloc] init]; - self.adImageView.userInteractionEnabled = NO; - self.adImageView.backgroundColor = [UIColor clearColor]; - - UITapGestureRecognizer *adImageTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapAdImage:)]; - [self.adImageView addGestureRecognizer: adImageTapGesture]; - - if ( self.replayOverlayView ) - { - [self.replayOverlayView removeFromSuperview]; - } - - self.replayOverlayView = [[ALCarouselReplayOverlayView alloc] initWithParentView: self]; - self.replayOverlayView.alpha = 0.0f; - self.replayOverlayView.userInteractionEnabled = YES; - [self.replayOverlayView.replayIconButton addTarget: self action: @selector(didTapReplayButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.replayOverlayView.replayButton addTarget: self action: @selector(didTapReplayButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.replayOverlayView.learnMoreIconButton addTarget: self action: @selector(didTapLearnMoreButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.replayOverlayView.learnMoreButton addTarget: self action: @selector(didTapLearnMoreButton:) forControlEvents: UIControlEventTouchUpInside]; - - [self addSubview: self.adImageView]; - [self addSubview: self.replayOverlayView]; -} - -#pragma mark - App Notifications - -- (void)appPaused:(NSNotification *)notification -{ - [self deactivateIfNeeded]; -} - -- (void)appResumed:(NSNotification *)notification -{ - [self reactivateIfNeeded]; -} - -#pragma mark - View Management - -- (void)willMoveToWindow:(UIWindow *)newWindow -{ - [super willMoveToWindow: newWindow]; - - // Will be moved into a window - if ( newWindow ) - { - [self reactivateIfNeeded]; - - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appPaused:) name: UIApplicationDidEnterBackgroundNotification object: nil]; - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appResumed:) name: UIApplicationDidBecomeActiveNotification object: nil]; - } - // Will be removed from window - else - { - [self deactivateIfNeeded]; - - [[NSNotificationCenter defaultCenter] removeObserver: self]; - } -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - self.videoView.frame = self.bounds; - - const CGFloat muteButtonWidth = kMuteWidth + kMuteButtonPadding; - const CGFloat muteButtonHeight = kMuteHeight + kMuteButtonPadding; - - CGRect muteFrame = CGRectZero; - muteFrame.origin.x = kMuteButtonMargin; - muteFrame.origin.y = CGRectGetMaxY(self.videoView.frame) - muteButtonHeight - kMuteButtonMargin; - muteFrame.size.width = muteButtonWidth; - muteFrame.size.height = muteButtonHeight; - self.muteButton.frame = muteFrame; - self.muteButton.imageEdgeInsets = UIEdgeInsetsMake(kMuteButtonPadding, 0.0f, 0.0f, kMuteButtonPadding); - - self.playButton.frame = CGRectMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds), kPlayReplayWidth, kPlayReplayHeight); - self.playButton.center = self.videoView.center; - - self.replayOverlayView.frame = self.bounds; - self.adImageView.frame = self.cardState.screenshot ? self.cardState.videoRect : self.bounds; -} - -// Entry points -- (void)renderViewForNativeAd:(ALNativeAd *)ad -{ - ALCarouselCardState *cardState = [ALCarouselCardState cardStateForSingleCard]; - [self renderViewForNativeAd: ad cardState: cardState]; -} - -- (void)renderViewForNativeAd:(ALNativeAd *)ad cardState:(ALCarouselCardState *)cardState -{ - if ( ad ) - { - self.ad = ad; - self.cardState = cardState; - [self createVideoPlayerIfNeeded]; - [self refresh]; - } - else - { - [self clearView]; - } -} - -- (void)refresh -{ - const ALNativeAd *ad = self.ad; - if ( ad ) - { - // If we get to this point, ad image is pre-cached - NSLog(@"Begin refresh media view for slot ID: %@ %@", ad.adIdNumber, ad.title); - - self.adImageView.userInteractionEnabled = YES; - - // Populate ad image behind replay overlay - if ( self.cardState.screenshot && !CGRectIsEmpty(self.cardState.videoRect) ) - { - // If this card has a video screenshot rendered, set that as the ad image - self.adImageView.image = self.cardState.screenshot; - self.adImageView.frame = self.cardState.videoRect; - } - else - { - // Else, just set the ad image to the default one - self.adImageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: ad.imageURL]]; - self.adImageView.frame = self.bounds; - } - - // If the replay overlay is supposed to be visible, show it and hide the video controls - if ( self.cardState.replayOverlayVisible ) - { - self.replayOverlayView.alpha = 1.0f; - self.playButton.alpha = 0.0f; - self.muteButton.alpha = 0.0f; - } - // Else, hide the replay overlay. Visibility of video controls will be determined if autoplay is on/off - else - { - self.replayOverlayView.alpha = 0.0f; - } - - // If this is the middle/single card, we give it special treatment - if ( self.cardState.currentlyActive ) - { - // If the video is pre-cached or we should stream - if ( [ad isVideoPrecached] ) - { - // Autoplay if required (if config says so, and replay overlay is not currently showing) - [self autoplayIfRequired]; - } - // Video is still pre-caching. Will show on top of ad image when pre-cached from carousel view - else - { - NSLog(@"Video still waiting to be pre-cached for slot (%@)...", ad.adIdNumber); - } - } - else - { - // No special treatment for non-middle cards - } - } - else - { - NSLog(@"Begin refresh for nil slot. Clearing view..."); - [self clearView]; - } -} - -#pragma mark - Video Action Methods - -- (void)autoplayIfRequired -{ - self.adImageView.userInteractionEnabled = NO; - - // Update the mute button regardless if we're autoplaying since we'll have to animate it regardless - [self updateMuteState]; - - // If the video is not waiting to be replayed - if ( !self.cardState.replayOverlayVisible ) - { - // If configuration says we should autoplay - if ( kIsAutoplay ) - { - [self playVideoIfInactive]; - } - else - { - // If we're not going to autoplay the video, animate in the video controls - [UIView animateWithDuration: 0.5f animations:^{ - self.playButton.alpha = 1.0f; - }]; - } - } -} - -- (void)playVideoIfInactive -{ - if ( [self isCurrentlyPlayingVideo] ) - { - NSLog(@"Attempting to play a video that's already playing"); - } - else - { - NSLog(@"Video play requested..."); - - self.videoView.playerLayer.backgroundColor = kVideoViewBackgroundWhilePlayingColor.CGColor; - self.videoView.backgroundColor = kVideoViewBackgroundWhilePlayingColor; - - // Prepare the view to play video - [UIView animateWithDuration: 1.0f animations:^{ - - self.muteButton.alpha = 1.0f; - self.playButton.alpha = 0.0f; - - // Crossfade the video in and the ad image out then autoplay the video if needed - self.adImageView.alpha = 0.0f; - self.videoView.alpha = 1.0f; - }]; - - self.adImageView.userInteractionEnabled = NO; - - // When replaying a video we do not fade out the replay overlay - self.replayOverlayView.alpha = 0.0f; - self.cardState.replayOverlayVisible = NO; - - // Attach new observer to get notified when video ends - [[NSNotificationCenter defaultCenter] addObserver: self - selector: @selector(playerItemDidReachEnd:) - name: AVPlayerItemDidPlayToEndTimeNotification - object: self.videoView.player.currentItem]; - - // Prepare the video - self.videoPlayer.mediaSource = self.ad.videoURL; - [self seekToPosition: self.cardState.lastMediaPlayerPosition]; - self.cardState.videoStarted = YES; - [self.videoPlayer playVideo]; - - - // Track the video start if we didn't track it yet - if ( !self.cardState.wasVideoStartTracked ) - { - NSLog(@"Tracking video start for native ad (%@)", self.ad.adIdNumber); - [self.sdk.postbackService dispatchPostbackAsync: self.ad.videoStartTrackingURL andNotify: nil]; - - self.cardState.videoStartTracked = YES; - } - } -} - -- (void)setInactive -{ - self.adImageView.alpha = 1.0f; - self.adImageView.userInteractionEnabled = YES; - self.videoView.alpha = 0.0f; - self.muteButton.alpha = 0.0f; - self.playButton.alpha = 0.0f; - - // Reset background colors - self.backgroundColor = kVideoViewBackgroundColor; - self.videoView.playerLayer.backgroundColor = kVideoViewBackgroundColor.CGColor; - self.videoView.backgroundColor = kVideoViewBackgroundColor; - - [self deactivateIfNeeded]; -} - -- (void)playerItemDidReachEnd:(NSNotification *)notification -{ - NSLog(@"Video finished playing for native ad (%@)", self.ad.adIdNumber); - - self.cardState.lastMediaPlayerPosition = 0.0f; - self.cardState.videoCompleted = YES; - self.cardState.replayOverlayVisible = YES; - - [UIView animateWithDuration: 0.5f animations:^{ - self.muteButton.alpha = 0.0f; - self.replayOverlayView.alpha = 1.0f; - }]; - - [self handleVideoStopPlaying]; -} - -#pragma mark - Action Methods - -- (void)didTapMuteButton:(UIButton *)muteButton -{ - self.cardState.muteState = self.cardState.muteState == ALMuteStateMuted ? ALMuteStateUnmuted : ALMuteStateMuted; - [self updateMuteState]; -} - -- (void)didTapPlayButton:(UIButton *)sender -{ - [self playVideoIfInactive]; -} - -- (void)didTapReplayButton:(UIButton *)sender -{ - [self playVideoIfInactive]; -} - -- (void)didTapLearnMoreButton:(UIButton *)sender -{ - NSLog(@"Redirecting from Learn More button"); - [self handleClick]; -} - -- (void)didTapVideo:(UITapGestureRecognizer *)tapGesture -{ - if ( kVideoClicksThrough ) - { - NSLog(@"Redirecting from video click"); - [self handleClick]; - [self setInactive]; - } - else - { - if ( [self isCurrentlyPlayingVideo] ) - { - [self setInactive]; - [UIView animateWithDuration: 0.5f animations:^{ - self.playButton.alpha = 1.0f; - }]; - } - else - { - [self playVideoIfInactive]; - } - } -} - -- (void)didTapAdImage:(UITapGestureRecognizer *)tapGesture -{ - NSLog(@"Redirecting from ad image click"); - [self handleClick]; -} - -- (void)handleClick -{ - if ( self.cardView ) - { - [self.cardView handleClickForAd: self.ad]; - } - else - { - [self.ad launchClickTarget]; - } -} - -#pragma mark - Video Utility Methods - -- (Float64)currentVideoPosition -{ - return CMTimeGetSeconds(self.videoView.player.currentTime); -} - -- (Float64)videoDuration -{ - return CMTimeGetSeconds(self.videoPlayer.playerAsset.duration); -} - -- (NSNumber *)percentViewed -{ - Float64 viewedRatio = [self currentVideoPosition] / [self videoDuration]; - return @( viewedRatio * 100 ); -} - -- (UIImage *)frameForVideoAtCurrentPosition -{ - AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset: self.videoPlayer.playerAsset]; - - // Set the tolerance so we have a precise screenshot - if ( [imageGenerator respondsToSelector: @selector(setRequestedTimeToleranceBefore:)] && - [imageGenerator respondsToSelector: @selector(setRequestedTimeToleranceAfter:)] ) - { - [imageGenerator setRequestedTimeToleranceBefore: kCMTimeZero]; - [imageGenerator setRequestedTimeToleranceAfter: kCMTimeZero]; - } - - return [UIImage imageWithCGImage: [imageGenerator copyCGImageAtTime: self.videoView.player.currentItem.currentTime - actualTime: nil - error: nil]]; -} - -- (void)handleVideoStopPlaying -{ - self.videoView.playerLayer.backgroundColor = kVideoViewBackgroundColor.CGColor; - - if ( kRenderVideoScreenshotAsFallbackImage ) - { - self.cardState.screenshot = [self frameForVideoAtCurrentPosition]; - self.adImageView.image = self.cardState.screenshot; - - // Save the video rect, so at layoutSubviews: in an inactive card, we know what aspect ratio size the screenshot - // should be rendered in. - self.cardState.videoRect = self.videoView.playerLayer.videoRect; - } - - [[NSNotificationCenter defaultCenter] removeObserver: self name: AVPlayerItemDidPlayToEndTimeNotification object: nil]; - - // Track video completion if we havn't already - if ( self.cardState.videoStarted ) - { - NSURL* postbackUrl = [self.ad videoEndTrackingURL: [[self percentViewed] unsignedIntegerValue] firstPlay: self.cardState.firstPlayback]; - [self.sdk.postbackService dispatchPostbackAsync: postbackUrl andNotify: nil]; - } - - self.cardState.firstPlayback = NO; -} - -- (BOOL)isCurrentlyPlayingVideo -{ - return self.videoView.player.rate > 0.0f; -} - -- (void)seekToPosition:(Float64)position -{ - CMTimeScale timeScale = self.videoView.player.currentItem.asset.duration.timescale; - CMTime time = CMTimeMakeWithSeconds(position, timeScale); - [self.videoView.player seekToTime: time toleranceBefore: kCMTimeZero toleranceAfter: kCMTimeZero]; -} - -- (void)updateMuteState -{ - ALMuteState currentState = self.cardState.muteState; - - // If the current state is unspecify, determine if it should be muted or unmuted according to settings - if ( currentState == ALMuteStateUnspecified ) - { - currentState = kConfigIsMuted ? ALMuteStateMuted : ALMuteStateUnmuted; - self.cardState.muteState = currentState; - } - - if ( currentState == ALMuteStateMuted ) - { - self.muteButton.selected = YES; - self.videoView.player.muted = YES; - } - else if ( currentState == ALMuteStateUnmuted ) - { - self.muteButton.selected = NO; - self.videoView.player.muted = NO; - } -} - -#pragma mark - Utility Methods - -- (void)clearView -{ - self.adImageView.image = nil; - self.adImageView.alpha = 0.0f; - self.adImageView.userInteractionEnabled = NO; - self.videoView.alpha = 0.0f; - self.replayOverlayView.alpha = 0.0f; - self.cardState = nil; -} - -// Called when resuming app or going back into the containing VC -- (void)reactivateIfNeeded -{ - if ( self.cardState.currentlyActive && [self.ad isVideoPrecached] ) - { - [self autoplayIfRequired]; - } -} - -// Called when pausing app or leaving VC *OR* when setting a card inactive -- (void)deactivateIfNeeded -{ - if ( [self isCurrentlyPlayingVideo] ) - { - self.cardState.lastMediaPlayerPosition = [self currentVideoPosition]; - - [self.videoPlayer stopVideo]; - [self handleVideoStopPlaying]; - } -} - -- (void)destroyVideoPlayer -{ - // We don't need a video player; remove any one left behind. - [self.videoPlayer stopVideo]; - self.videoPlayer = nil; - - [self.videoView removeFromSuperview]; - self.videoView = nil; - - [self.muteButton removeFromSuperview]; - [self.playButton removeFromSuperview]; - - self.playButton = nil; - self.muteButton = nil; -} - -- (void)createVideoPlayerIfNeeded -{ - [self destroyVideoPlayer]; - - // Create video player only for middle card - if ( self.cardState.currentlyActive && [self.ad isVideoPrecached] ) - { - self.videoPlayer = [[ALNativeAdVideoPlayer alloc] initWithMediaSource: nil]; - self.videoView.player.actionAtItemEnd = AVPlayerActionAtItemEndPause; - self.videoView.playerLayer.backgroundColor = [UIColor clearColor].CGColor; - - self.videoView = self.videoPlayer.videoView; - [self.videoView.playerLayer setNeedsDisplay]; - self.videoView.backgroundColor = kVideoViewBackgroundColor; - - self.muteButton = [[UIButton alloc] init]; - self.muteButton.alpha = 0.0f; - [self.muteButton addTarget: self action: @selector(didTapMuteButton:) forControlEvents: UIControlEventTouchUpInside]; - - self.playButton = [[UIButton alloc] init]; - self.playButton.alpha = 0.0f; - [self.playButton addTarget: self action: @selector(didTapPlayButton:) forControlEvents: UIControlEventTouchUpInside]; - - UITapGestureRecognizer *videoTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapVideo:)]; - [self.videoView addGestureRecognizer: videoTapGesture]; - - [self insertSubview: self.videoView belowSubview: self.adImageView]; - [self insertSubview: self.playButton aboveSubview: self.adImageView]; - [self insertSubview: self.muteButton aboveSubview: self.videoView]; - - // Popualte the assets - [self.playButton setImage: [UIImage imageNamed: @"applovin_card_play"] forState: UIControlStateNormal]; - [self.muteButton setImage: [UIImage imageNamed: @"applovin_card_unmuted"] forState: UIControlStateNormal]; - [self.muteButton setImage: [UIImage imageNamed: @"applovin_card_muted"] forState: UIControlStateSelected]; - } -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.h deleted file mode 100644 index 7c14e79d75..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// ALCarouselReplayOverlayView.h -// sdk -// -// Created by Thomas So on 4/22/15. -// -// - -@import UIKit; -#import "ALCarouselMediaView.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * This view provides a few buttons to allow the user to replay or click through an ad. - */ -@interface ALCarouselReplayOverlayView : UIView - -@property (strong, nonatomic) UIView *overlay; -@property (strong, nonatomic) UIButton *replayButton; -@property (strong, nonatomic) UIButton *replayIconButton; -@property (strong, nonatomic) UIButton *learnMoreButton; -@property (strong, nonatomic) UIButton *learnMoreIconButton; - -- (instancetype)initWithParentView:(ALCarouselMediaView *)parentView; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.m deleted file mode 100644 index 02a4d8768b..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselReplayOverlayView.m +++ /dev/null @@ -1,99 +0,0 @@ -// -// ALCarouselReplayOverlayView.m -// sdk -// -// Created by Thomas So on 4/22/15. -// -// - -#import "ALCarouselReplayOverlayView.h" -#import "ALCarouselViewSettings.h" - -@interface ALCarouselReplayOverlayView() -@property (weak, nonatomic) ALCarouselMediaView *mediaView; -@end - -@implementation ALCarouselReplayOverlayView - -#pragma mark - Initialization - -- (instancetype)initWithParentView:(ALCarouselMediaView *)parentView -{ - self = [super init]; - if ( self ) - { - self.mediaView = parentView; - - self.backgroundColor = [UIColor clearColor]; - - self.overlay = [[UIView alloc] init]; - - self.overlay.backgroundColor = kReplayOverlayBackgroundColor; - self.overlay.alpha = kConfigReplayOverlayAlpha; - [self addSubview: self.overlay]; - - self.replayIconButton = [[UIButton alloc] init]; - [self addSubview: self.replayIconButton]; - - self.replayButton = [[UIButton alloc] init]; - [self addSubview: self.replayButton]; - - self.learnMoreIconButton = [[UIButton alloc] init]; - [self addSubview: self.learnMoreIconButton]; - - self.learnMoreButton = [[UIButton alloc] init]; - [self addSubview: self.learnMoreButton]; - - [self.replayIconButton setTintColor: kButtonHighlightTint]; - [self.replayButton setTitleColor: kReplayTextColor forState: UIControlStateNormal]; - [self.replayButton setTitleColor: kButtonHighlightTint forState: UIControlStateHighlighted]; - [self.learnMoreButton setTitleColor: kReplayTextColor forState: UIControlStateNormal]; - [self.learnMoreButton setTitleColor: kButtonHighlightTint forState: UIControlStateHighlighted]; - [self.learnMoreIconButton setTintColor: kButtonHighlightTint]; - - [self.replayIconButton setImage: [UIImage imageNamed: @"applovin_card_replay"] forState: UIControlStateNormal]; - [self.learnMoreIconButton setImage: [UIImage imageNamed: @"applovin_card_learn_more"] forState: UIControlStateNormal]; - - [self.replayButton setTitle: kTextReplayVideo forState: UIControlStateNormal]; - [self.learnMoreButton setTitle: kTextLearnMore forState: UIControlStateNormal]; - } - return self; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - self.overlay.frame = self.bounds; - - const CGFloat replayButtonWidth = [self.replayButton sizeThatFits: CGSizeMake(CGFLOAT_MAX, 0.0f)].width; - const CGFloat totalReplayWidth = kPlayReplayWidth + kPadding + replayButtonWidth; - - const CGFloat learnMoreButtonWidth = [self.learnMoreButton sizeThatFits: CGSizeMake(CGFLOAT_MAX, 0.0f)].width; - const CGFloat totalLearnMoreWidth = kPlayReplayWidth + kPadding + learnMoreButtonWidth; - - const CGFloat totalContentHeight = (2*kPlayReplayHeight) + kPadding; - - // We will center and align depending on which button has the longer total width - const CGFloat longerWidth = totalReplayWidth >= totalLearnMoreWidth ? totalReplayWidth : totalLearnMoreWidth; - - self.replayIconButton.frame = CGRectMake(CGRectGetMidX(self.frame) - longerWidth/2.0f, - CGRectGetMidY(self.frame) - totalContentHeight/2.0f, - kPlayReplayWidth, - kPlayReplayHeight); - self.replayButton.frame = CGRectMake(CGRectGetMaxX(self.replayIconButton.frame) + kPadding, - CGRectGetMinY(self.replayIconButton.frame), - replayButtonWidth, - kPlayReplayHeight); - - self.learnMoreIconButton.frame = CGRectMake(CGRectGetMidX(self.frame) - longerWidth/2.0f, - CGRectGetMaxY(self.replayIconButton.frame) + kPadding, - kPlayReplayWidth, - kPlayReplayHeight); - self.learnMoreButton.frame = CGRectMake(CGRectGetMaxX(self.learnMoreIconButton.frame) + kPadding, - CGRectGetMaxY(self.replayIconButton.frame) + kPadding, - learnMoreButtonWidth, - kPlayReplayHeight); -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.h deleted file mode 100644 index ba438deb10..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// ALCarouselView.h -// -// Created by Thomas So on 3/30/15. -// Copyright (c) 2015, AppLovin Corporation. All rights reserved. -// - -@import AppLovinSDK; - -NS_ASSUME_NONNULL_BEGIN - -/** - * This class is used to display native ads to the user. - */ -@interface ALCarouselView : UIView - -/** - * An object conforming to the ALNativeAdGroupLoadDelegate protocol, which, if set, will be notified of ad load events. - */ -@property (weak, nonatomic, nullable) id loadDelegate; - -/** - * The current native ad(s) being displayed. - */ -@property (strong, nonatomic, readonly) NSArray *nativeAds; - -- (instancetype)initWithFrame:(CGRect)frame; -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk; -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk nativeAds:(NSArray *)nativeAds; -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.m deleted file mode 100644 index de4b17b0b3..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALCarouselView.m +++ /dev/null @@ -1,642 +0,0 @@ -// -// ALCarouselView.m -// -// Created by Thomas So on 3/30/15. -// Copyright (c) 2015, AppLovin Corporation. All rights reserved. -// - -@import AppLovinSDK; -#import "ALCarouselView.h" -#import "ALCarouselView+Internal.h" -#import "UIView+ALActivityIndicator.h" -#import "ALCarouselCardView.h" -#import "ALCarouselCardState.h" -#import "ALCarouselViewModel.h" -#import "ALCarouselViewSettings.h" - -@class ALCarouselView; - -/** - * This class acts as an intermediary between pre-cache events of slots and which card to notify. - */ -@interface ALCarouselPrecacheRouter : NSObject - -@property (copy, nonatomic) NSString *tag; -@property (weak, nonatomic) ALCarouselView *carouselView; - -- (instancetype)initWithCarouselView:(ALCarouselView *)carouselView; - -@end - -@interface ALCarouselView() - -@property (strong, nonatomic) ALSdk *sdk; -@property (weak, nonatomic) ALPostbackService *postbackService; - -@property (weak, atomic) NSArray *previousNativeAdsRendered; -@property (strong, nonatomic) ALCarouselViewModel *carouselModel; -@property (assign, nonatomic) NSInteger currentAdIndex; - -@property (strong, nonatomic) ALCarouselPrecacheRouter *precacheRouter; - -// This array has 5 card objets that are used to render the ad -@property (strong, nonatomic) NSArray *cardViews; -@property (strong, nonatomic) UIView *contentView; -@property (strong, nonatomic) UIPanGestureRecognizer *panGesture; - -@end - -#pragma mark ALCarouselView - -@implementation ALCarouselView -static NSString * const TAG = @"ALCarouselView"; - -// Card constants -static NSInteger const kNumSideCards = 2; -static NSInteger const kNumCards = 5; -static NSInteger const kMidCardIndex = 2; - -#pragma mark - Initialization - -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder: aDecoder]; - if ( self ) - { - [self baseInitWithSdk: [ALSdk shared]]; - } - return self; -} - -- (instancetype)init -{ - self = [super init]; - if (self) - { - self.sdk = [ALSdk shared]; - } - return self; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - return [self initWithFrame: frame sdk: [ALSdk shared]]; -} - -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk -{ - return [self initWithFrame: frame sdk: sdk nativeAds: @[]]; -} - -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk nativeAds:(NSArray *)nativeAds -{ - self = [super initWithFrame: frame]; - if ( self ) - { - [self baseInitWithSdk: sdk]; - self.nativeAds = nativeAds; - } - return self; -} - -- (void)baseInitWithSdk:(ALSdk *)sdk -{ - self.sdk = sdk; - self.postbackService = sdk.postbackService; - - self.currentAdIndex = 0; - - self.precacheRouter = [[ALCarouselPrecacheRouter alloc] initWithCarouselView: self]; - - // Setup View - self.userInteractionEnabled = YES; - self.clipsToBounds = YES; - self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - self.backgroundColor = kCarouselBackgroundColor; - - self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; - self.panGesture.delegate = self; - self.panGesture.delaysTouchesBegan = NO; - self.panGesture.delaysTouchesEnded = NO; - [self addGestureRecognizer: self.panGesture]; - - self.contentView = [[UIView alloc] init]; - self.contentView.backgroundColor = kCarouselBackgroundColor; - [self addSubview: self.contentView]; - - NSMutableArray* tempCards = [NSMutableArray arrayWithCapacity: kNumCards]; - for ( NSInteger i = 0; i < kNumCards; ++i ) - { - ALCarouselCardView *cardView = [[ALCarouselCardView alloc] initWithSdk: sdk]; - cardView.backgroundColor = [UIColor clearColor]; - cardView.hidden = YES; - - - [self.contentView addSubview: cardView]; - - [tempCards addObject: cardView]; - } - - self.cardViews = [NSArray arrayWithArray: tempCards]; -} - --(void) didMoveToSuperview -{ - [super didMoveToSuperview]; - - // If there are attached from initialization - if ( self.nativeAds.count > 0 ) - { - // All of the objects in the array are checked to be of proper type in setter. Render. - [self renderAdsIfNeeded]; - } - // If there isn't currently any native ad(s) attached, load one. - else - { - [self al_showActivityIndicator]; - - // AppLovin SDK has deprecated loading of multiple native ads - [self.sdk.nativeAdService loadNextAdAndNotify: self]; - //[self.sdk.nativeAdService loadNativeAdGroupOfCount: kNativeAdsToLoadCount andNotify: self]; - } -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - const CGFloat cardWidth = (CGRectGetWidth(self.bounds) * kCardWidthPercentage) - (2 * kCardMargin); - const CGFloat contentWidth = kNumCards * cardWidth; - - CGRect contentFrame = CGRectZero; - contentFrame.origin.x = CGRectGetMidX(self.bounds) - (contentWidth/2); - contentFrame.size.width = contentWidth; - contentFrame.size.height = CGRectGetHeight(self.bounds); - self.contentView.frame = contentFrame; - - CGFloat currentX = 0.0f; - for ( ALCarouselCardView *cardView in self.cardViews ) - { - cardView.frame = CGRectMake(currentX, 0.0f, cardWidth, CGRectGetHeight(self.bounds)); - currentX += cardWidth; - } - - // Activity Views from category - self.activityIndicatorOverlay.frame = self.bounds; - self.activityIndicator.center = self.activityIndicatorOverlay.center; -} - -#pragma mark - Native Ad Load Delegate - -- (void)nativeAdService:(ALNativeAdService *)service didLoadAds:(NSArray *)ads -{ - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - - self.nativeAds = ads; - [self renderAdsIfNeeded]; - - @try - { - if ( [(id)self.loadDelegate respondsToSelector: @selector(nativeAdService:didLoadAds:)] ) - { - [self.loadDelegate nativeAdService: service didLoadAds: ads]; - } - } - @catch (NSException *exception) - { - NSLog(@"Unable to notify native ad load delegate because of exception: %@", exception); - } - }]; -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToLoadAdsWithError:(NSInteger)code -{ - NSLog(@"Native ad service did fail to load native ad with error: %ld", code); - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - - @try - { - if ( [(id)self.loadDelegate respondsToSelector: @selector(nativeAdService:didFailToLoadAdsWithError:)] ) - { - [self.loadDelegate nativeAdService: service didFailToLoadAdsWithError: code]; - } - } - @catch (NSException *exception) - { - NSLog(@"Unable to notify native ad load delegate about failing to load because of exception: %@", exception); - } - }]; -} - -#pragma mark - View Rendering - -- (void)renderAdsIfNeeded -{ - if ( [self.nativeAds isEqual: self.previousNativeAdsRendered] ) - { - NSLog(@"Attempting to re-render native ad(s)"); - } - else - { - // Keep track of native ad(s) rendered to prevent re-rendering - self.previousNativeAdsRendered = self.nativeAds; - - self.carouselModel = [[ALCarouselViewModel alloc] initWithNativeAds: self.nativeAds]; - - self.panGesture.enabled = self.nativeAds.count > 1; // Don't allow swiping if only one card - - self.currentAdIndex = 0; - - [self refreshView]; - } -} - -- (void)refreshView -{ - NSLog(@"Begin refreshing carousel view for number of native ads: %lu", self.nativeAds.count); - - // Update/save states before refreshing each card - for ( ALCarouselCardView *cardView in self.cardViews ) - { - [cardView.mediaView setInactive]; - } - - for ( NSInteger cardIndex = 0; cardIndex < kNumCards ; ++cardIndex ) - { - NSLog(@"Begin refreshing for card at index %ld", cardIndex); - - ALCarouselCardView *cardView = self.cardViews[cardIndex]; - - // Determine what slot should be displaying in the card with index 'cardIndex' now - // Please Note: Will return an out-of-bounds if we're not supposed to render ad for card at this index - NSInteger adIndex = [self adIndexForCardIndex: cardIndex]; - - // If ad exists for this card view, render - if ( (adIndex >= 0) && (adIndex < self.nativeAds.count) ) - { - NSLog(@"Refreshing card view at index: %ld with slot at index: %ld", cardIndex, adIndex); - ALNativeAd *ad = self.nativeAds[adIndex]; - - ALCarouselCardState *cardState = [self.carouselModel cardStateAtNativeAdIndex: adIndex]; - cardState.currentlyActive = (cardIndex == kMidCardIndex); - - if ( [ad isImagePrecached] ) - { - NSLog(@"Card at index: %ld currently has its images pre-cached", cardIndex); - - [cardView renderViewForNativeAd: ad cardState: cardState]; - - // Only middle (active) card can be clicked on - cardView.userInteractionEnabled = cardState.currentlyActive; - cardView.hidden = NO; - - if ( cardState.currentlyActive ) - { - // Handle events when middle card is displayed - [cardView trackImpression]; - } - } - // If images are not pre-cached, then videos are not pre-cached as well - else - { - NSLog(@"Card at index: %ld is not pre-cached", cardIndex); - - [cardView clearView]; - [cardView al_showActivityIndicator]; - cardView.hidden = NO; - - if ( cardState.precaching ) - { - NSLog(@"Card at index: %ld is already currently pre-caching", cardIndex); - } - else - { - cardState.precaching = YES; - - NSLog(@"Begin pre-caching for card at index: %ld", cardIndex); - [self.sdk.nativeAdService precacheResourcesForNativeAd: ad andNotify: self.precacheRouter]; - } - } - } - // Slot does not exist for this card view, hide - else - { - NSLog(@"Hiding card at card index: %ld", cardIndex); - - [cardView clearView]; - cardView.hidden = YES; - - if ( cardIndex == kMidCardIndex ) - { - NSLog(@"Hiding middle card because of nil ad."); - } - } - } - - [self al_hideActivityIndicatorAnimated: YES]; - - NSLog(@"Finish refreshing carousel view"); -} - -- (void)clearView -{ - for ( ALCarouselCardView *cardView in self.cardViews ) - { - [cardView clearView]; - } - [self.carouselModel removeAllObjects]; -} - -#pragma mark - Overridden Getters/Setters - -- (void)setNativeAds:(NSArray * __nullable)nativeAds -{ - if ( self.nativeAds.count > 0 ) - { - // Check if array contains objects of the proper ad type - for ( id obj in self.nativeAds ) - { - if ( ![obj isKindOfClass: [ALNativeAd class]] ) - { - // Found an object of invalid type - NSLog(@"Found an object of invalid type (%@) in nativeAds", NSStringFromClass([obj class])); - - return; - } - } - } - else - { - // We clear the view if native ads is set to an empty array - NSLog(@"Setting native ads of count 0. Clearing view..."); - [self clearView]; - } - - _nativeAds = nativeAds; -} - -- (void)setCurrentAdIndex:(NSInteger)currentAdIndex -{ - if ( currentAdIndex < self.nativeAds.count ) - { - if ( self.currentAdIndex == currentAdIndex ) - { - NSLog(@"Setting same current ad index of %ld", currentAdIndex); - } - else - { - NSLog(@"Setting new current ad index of %ld", currentAdIndex); - - _currentAdIndex = currentAdIndex; - - [self refreshView]; - } - } - else - { - NSLog(@"Setting out-of-bounds index of %ld", currentAdIndex); - } -} - -#pragma mark - Utility - -- (NSInteger)adIndexForCardIndex:(NSUInteger)cardIndex -{ - return self.currentAdIndex + cardIndex - kNumSideCards; -} - -#pragma mark - Gesture Recognizers - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - if ( [gestureRecognizer isEqual: self.panGesture] ) - { - // Our pan gesture should only recognize horizontal pans - CGPoint translation = [self.panGesture velocityInView: self]; - return fabs(translation.y) < fabs(translation.x); - } - - return YES; -} - -- (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer -{ - switch ( recognizer.state ) - { - case UIGestureRecognizerStateChanged: - { - CGFloat xOffset = [recognizer translationInView: self].x; - self.contentView.frame = CGRectOffset(self.contentView.frame, xOffset, 0.0f); - - [recognizer setTranslation: CGPointZero inView: self]; - - break; - } - case UIGestureRecognizerStateEnded: - { - const CGFloat cardWidth = (CGRectGetWidth(self.bounds) * kCardWidthPercentage) - (2 * kCardMargin); - const CGFloat contentOffset = fabs(self.center.x - self.contentView.center.x); - const CGFloat percentageSwiped = 1.0f - (contentOffset/CGRectGetWidth(self.bounds)); - const CGFloat springDuration = percentageSwiped * kSpringDuration; - - const BOOL exceedsThreshold = contentOffset > kConfigSwipeThreshold; - const BOOL leftToRight = [recognizer velocityInView: self].x > 0.0f; - - // If user is swiping left to right - if ( leftToRight ) - { - // If the middle card has a slot to the left of it, then execute the swipe - if ( self.currentAdIndex >= 1 && exceedsThreshold ) - { - [UIView animateWithDuration: springDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningGoNextCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake( (CGRectGetWidth(self.frame)/2.0f) + cardWidth, self.contentView.center.y); - } - completion: ^(BOOL finished) { - - if ( finished ) - { - --self.currentAdIndex; - [self setNeedsLayout]; - } - }]; - } - // There are no slots to the left of the middle card anymore, spring back - else - { - [UIView animateWithDuration: kSpringDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningReturnSameCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake(0.5f * CGRectGetWidth( self.frame ), self.contentView.center.y); - } - completion:nil]; - } - } - // We are swiping right to left - else - { - // If there is a slot to the right of the middle card, execute the swipe - if ( self.currentAdIndex < [self.carouselModel nativeAdsCount]-1 && exceedsThreshold ) - { - [UIView animateWithDuration: springDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningGoNextCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake( (CGRectGetWidth(self.frame)/2.0f) - cardWidth, self.contentView.center.y); - } - completion:^(BOOL finished) { - - if ( finished ) - { - ++self.currentAdIndex; - [self setNeedsLayout]; - } - }]; - } - // There are no slots to the right of the middle card anymore. Spring back - else - { - [UIView animateWithDuration: kSpringDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningReturnSameCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake(0.5f * CGRectGetWidth( self.frame ), self.contentView.center.y); - } - completion:nil]; - } - } - break; - } - default: - { - break; - } - } -} - -@end - -#pragma mark ALCarouselPrecacheRouter - -@implementation ALCarouselPrecacheRouter - -#pragma mark - Initialization - -- (instancetype)initWithCarouselView:(ALCarouselView *)carouselView -{ - self = [super init]; - - if ( self ) - { - self.tag = @"ALCarouselPrecacheRouter"; - self.carouselView = carouselView; - } - - return self; -} - -#pragma mark - Precache Delegate Methods - -- (void)nativeAdService:(ALNativeAdService *)service didPrecacheImagesForAd:(ALNativeAd *)ad -{ - NSLog(@"Finished pre-caching images for slot (%@). Rendering...", ad.adIdNumber); - - const NSUInteger index = [self.carouselView.nativeAds indexOfObject: ad]; - - if ( index != NSNotFound ) - { - const NSInteger cardIndex = [self cardIndexForAdIndex: index]; - ALCarouselCardView* cardView = self.carouselView.cardViews[cardIndex]; - ALCarouselViewModel* model = self.carouselView.carouselModel; - ALCarouselCardState* cardState = [model cardStateAtNativeAdIndex: index]; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [cardView renderViewForNativeAd: ad cardState: cardState]; - - if (cardIndex == kMidCardIndex) { - [cardView trackImpression]; - } - - cardView.hidden = NO; - }]; - } - else - { - NSLog(@"Finished pre-caching images for ad (%@). Card is not on screen, stashing...", ad.adIdNumber); - } -} - -- (void)nativeAdService:(ALNativeAdService *)service didPrecacheVideoForAd:(ALNativeAd *)ad -{ - if ( ad.videoURL ) - { - const NSUInteger index = [self.carouselView.nativeAds indexOfObject: ad]; - ALCarouselCardState *cardState = [self.carouselView.carouselModel cardStateAtNativeAdIndex: index]; - - // If video is loaded for a currently active ad, render the slot - if ( index != NSNotFound && cardState.currentlyActive ) - { - NSLog(@"Finished pre-caching for slot (%@) with valid video in active card", ad.adIdNumber); - - const NSInteger cardIndex = [self cardIndexForAdIndex: index]; - ALCarouselCardView *cardView = self.carouselView.cardViews[cardIndex]; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - - [cardView.mediaView renderViewForNativeAd: ad cardState: cardState]; - }]; - } - else - { - NSLog(@"Finished pre-caching video for ad (%@). Card is not on screen, stashing...", ad.adIdNumber); - } - } - else - { - // Finished pre-caching for slot without video - NSLog(@"Finished pre-caching for ad (%@) without video", ad.adIdNumber); - } - - [self.carouselView.carouselModel cardStateForNativeAd: ad].precaching = NO; -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToPrecacheImagesForAd:(ALNativeAd *)ad withError:(NSInteger)errorCode -{ - // Have activity indicator remain on card - [self.carouselView.carouselModel cardStateForNativeAd: ad].precaching = YES; - - NSLog(@"Failed to precache images for ad (%@) with error code: %ld", ad.adIdNumber, errorCode); -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToPrecacheVideoForAd:(ALNativeAd *)ad withError:(NSInteger)errorCode -{ - // If the slot already has its images pre-cached, it means video failed to pre-cache. Just ignore that - [self.carouselView.carouselModel cardStateForNativeAd: ad].precaching = NO; - - NSLog(@"Failed to precache video for ad (%@) with error code: %ld", ad.adIdNumber, errorCode); -} - -#pragma mark - Utility - -- (NSUInteger)cardIndexForAdIndex:(NSUInteger)slotIndex -{ - return kMidCardIndex + slotIndex - self.carouselView.currentAdIndex; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.h deleted file mode 100644 index fd5806828b..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// ALVideoView.h -// sdk -// -// Created by Matt Szaro on 6/23/14. -// -// - -@import AppLovinSDK; -@import AVFoundation; - -NS_ASSUME_NONNULL_BEGIN - -@interface ALNativeAdVideoView : UIView - -@property (strong, nonatomic, readonly) AVPlayer *player; -@property (strong, nonatomic, readonly) AVPlayerLayer* playerLayer; - -- (instancetype)initWithPlayer:(AVPlayer *)aPlayer; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.m deleted file mode 100644 index 279a6321fe..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/Carousel UI/Views/ALNativeAdVideoView.m +++ /dev/null @@ -1,48 +0,0 @@ -// -// ALVideoView.m -// sdk -// -// Created by Matt Szaro on 6/23/14. -// -// - -#import "ALNativeAdVideoView.h" - -@interface ALNativeAdVideoView() -@property (strong, nonatomic, readwrite) AVPlayer *player; -@end - -@implementation ALNativeAdVideoView -@dynamic player, playerLayer; - --(instancetype) initWithPlayer:(AVPlayer *)aPlayer -{ - self = [super init]; - if(self) - { - self.player = aPlayer; - } - return self; -} - -+(Class) layerClass -{ - return [AVPlayerLayer class]; -} - --(AVPlayerLayer*) playerLayer -{ - return (AVPlayerLayer*) self.layer; -} - --(AVPlayer*) player -{ - return self.playerLayer.player; -} - --(void) setPlayer: (AVPlayer *) aPlayer -{ - self.playerLayer.player = aPlayer; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.h deleted file mode 100644 index 2b720eab1e..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// ALDemoArticle.h -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface ALDemoArticle : NSObject - -@property (nonatomic, copy) NSString *title; -@property (nonatomic, copy) NSString *pubDate; -@property (nonatomic, copy) NSString *creator; -@property (nonatomic, copy) NSString *articleDescription; -@property (nonatomic, strong) NSURL *link; - -@property (nonatomic, assign) BOOL isAd; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.m deleted file mode 100644 index 2b24785788..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoArticle.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// ALDemoArticle.m -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALDemoArticle.h" - -@implementation ALDemoArticle - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.h deleted file mode 100644 index 0b76784375..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// ALDemoRSSFeedRetriever.h -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import -#import "ALDemoArticle.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ALDemoRSSFeedRetriever : NSObject - -typedef void(^ALDemoRSSFeedRetrieverBlock)(NSError *__nullable error, NSArray *articles); - -+ (ALDemoRSSFeedRetriever *)sharedRetriever; -- (void)startParsingWithCompletion:(ALDemoRSSFeedRetrieverBlock)completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.m deleted file mode 100644 index 5d039dfefb..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Feed/RSS Feed Parsing/ALDemoRSSFeedRetriever.m +++ /dev/null @@ -1,121 +0,0 @@ -// -// ALDemoRSSFeedRetriever.m -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALDemoRSSFeedRetriever.h" - -@interface ALDemoRSSFeedRetriever() -@property (nonatomic, copy, nullable) NSString *currentElementName; -@property (nonatomic, strong, nullable) ALDemoArticle *currentArticle; - -@property (nonatomic, strong) NSMutableArray *articles; -@property (nonatomic, copy) ALDemoRSSFeedRetrieverBlock completionBlock; -@end - -@implementation ALDemoRSSFeedRetriever -static NSString *const kRSSFeedURL = @"https://blog.applovin.com/feed/"; - -+ (ALDemoRSSFeedRetriever *)sharedRetriever -{ - static dispatch_once_t pred; - static ALDemoRSSFeedRetriever *manager = nil; - dispatch_once(&pred, ^{ - manager = [[self alloc] init]; - }); - return manager; -} - -- (instancetype)init -{ - self = [super init]; - if ( self ) - { - self.articles = [NSMutableArray array]; - } - return self; -} - -- (void)startParsingWithCompletion:(ALDemoRSSFeedRetrieverBlock)completion -{ - // Do not retrieve if we already have retrieved some artivcles, just call completion - if ( self.articles.count > 0 ) - { - completion( nil, [NSArray arrayWithArray: self.articles] ); - } - else - { - self.completionBlock = completion; - - NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL: [NSURL URLWithString: kRSSFeedURL]]; - [parser setDelegate: self]; - [parser parse]; - } -} - -#pragma mark - Parser Delegate - -- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict -{ - self.currentElementName = elementName; - if ( [elementName isEqualToString: @"item"] ) - { - // Start of the parsing of a new article - - if ( self.articles.count == 3 ) - { - // Lets place an ad in the 4th slot - ALDemoArticle *adFauxArticle = [[ALDemoArticle alloc] init]; - adFauxArticle.isAd = YES; - [self.articles addObject: adFauxArticle]; - } - - self.currentArticle = [[ALDemoArticle alloc] init]; - [self.articles addObject: self.currentArticle]; - } -} - -- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string -{ - if ( self.currentArticle ) - { - if ( [self.currentElementName isEqualToString: @"title"] ) - { - self.currentArticle.title = string; - } - else if ( [self.currentElementName isEqualToString: @"link"] ) - { - self.currentArticle.link = [NSURL URLWithString: string]; - } - else if ( [self.currentElementName isEqualToString: @"pubDate"] ) - { - self.currentArticle.pubDate = [string substringToIndex: 11]; - } - else if ( [self.currentElementName isEqualToString: @"dc:creator"] ) - { - self.currentArticle.creator = string; - } - else if ( [self.currentElementName isEqualToString: @"description"] ) - { - self.currentArticle.articleDescription = [string stringByReplacingOccurrencesOfString: @"[…]" withString: @"..."]; - } - - // Reset current element name after we finish setting it - self.currentElementName = @""; - } -} - -- (void)parserDidEndDocument:(NSXMLParser *)parser -{ - self.completionBlock( nil, [NSArray arrayWithArray: self.articles] ); -} - -- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError -{ - self.completionBlock( parseError, @[] ); -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.h b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.h deleted file mode 100644 index d49d97af19..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// ALDemoNativeAdProgrammaticViewController.h -// iOS-SDK-Demo -// -// Created by Thomas So on 9/24/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALBaseAdViewController.h" -#import "ALCarouselMediaView.h" - -@interface ALDemoNativeAdProgrammaticViewController : ALBaseAdViewController - -@property (nonatomic, strong) IBOutlet UIBarButtonItem *precacheButton; -@property (nonatomic, strong) IBOutlet UIBarButtonItem *showButton; - -@property (nonatomic, strong) IBOutlet UILabel *impressionStatusLabel; - -@property (nonatomic, strong) IBOutlet UIImageView *appIcon; -@property (nonatomic, strong) IBOutlet UILabel *titleLabel; -@property (nonatomic, strong) IBOutlet UIImageView *rating; -@property (nonatomic, strong) IBOutlet UILabel *descriptionLabel; -@property (nonatomic, strong) IBOutlet ALCarouselMediaView *mediaView; -@property (nonatomic, strong) IBOutlet UIButton *ctaButton; - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.m b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.m deleted file mode 100644 index d1b9ede32e..0000000000 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/AppLovin/Native Ads/Programmatic/ALDemoNativeAdProgrammaticViewController.m +++ /dev/null @@ -1,174 +0,0 @@ -// -// ALDemoNativeAdProgrammaticViewController.m -// iOS-SDK-Demo -// -// Created by Thomas So on 9/24/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALDemoNativeAdProgrammaticViewController.h" -#import - -@interface ALDemoNativeAdProgrammaticViewController() -@property (nonatomic, strong) ALNativeAd *cachedNativeAd; -@property (nonatomic, strong) ALNativeAd *nativeAd; -@end - -// Additional documentation - https://applovin.com/integration#iosNative - -@implementation ALDemoNativeAdProgrammaticViewController - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.appIcon.layer.masksToBounds = YES; - self.appIcon.layer.cornerRadius = 3.0f; - - self.ctaButton.layer.masksToBounds = YES; - self.ctaButton.layer.cornerRadius = 3.0f; - - [self setUIElementsHidden: YES]; -} - -#pragma mark - Action Methods - -- (IBAction)loadNativeAd:(id)sender -{ - self.precacheButton.enabled = NO; - self.showButton.enabled = NO; - - self.impressionStatusLabel.text = @"No impression to track"; - - [[ALSdk shared].nativeAdService loadNextAdAndNotify: self]; -} - -- (IBAction)precacheNativeAd:(id)sender -{ - // You can use our pre-caching to retrieve assets (app icon, ad image, ad video) locally. OR you can do it with your preferred caching framework. - // iconURL, imageURL, videoURL needs to be retrieved manually before you can render them - - [[ALSdk shared].nativeAdService precacheResourcesForNativeAd: self.nativeAd andNotify: self]; -} - -- (IBAction)showNativeAd:(id)sender -{ - self.nativeAd = self.cachedNativeAd; - - self.appIcon.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: self.nativeAd.iconURL]]; // Local URL - self.titleLabel.text = self.nativeAd.title; - self.descriptionLabel.text = self.nativeAd.descriptionText; - [self.ctaButton setTitle: self.nativeAd.ctaText forState: UIControlStateNormal]; - - NSString *filename = [NSString stringWithFormat: @"Star_Sprite_%@", self.nativeAd.starRating.stringValue]; - self.rating.image = [UIImage imageNamed: filename]; - - // NOTE - Videos have aspect ratio of 1:1.85 - [self.mediaView renderViewForNativeAd: self.nativeAd]; - - [self setUIElementsHidden: NO]; - - // - // You are responsible for firing impressions - // - [self trackImpression: self.nativeAd]; - - [self.view layoutIfNeeded]; -} - -- (IBAction)ctaPressed:(id)sender -{ - [self.nativeAd launchClickTarget]; -} - -#pragma mark - Impressing Tracking - -- (void)trackImpression:(ALNativeAd *)ad -{ - // Callbacks may not happen on main queue - dispatch_async(dispatch_get_main_queue(), ^{ - self.impressionStatusLabel.text = @"Tracking impression..."; - }); - - [ad trackImpressionAndNotify: self]; -} - -- (void)postbackService:(ALPostbackService *)postbackService didExecutePostback:(NSURL *)postbackURL -{ - // Callbacks may not happen on main queue - dispatch_async(dispatch_get_main_queue(), ^{ - // Impression tracked! - self.impressionStatusLabel.text = @"Impression tracked"; - }); -} - -- (void)postbackService:(ALPostbackService *)postbackService didFailToExecutePostback:(nullable NSURL *)postbackURL errorCode:(NSInteger)errorCode -{ - // Callbacks may not happen on main queue - dispatch_async(dispatch_get_main_queue(), ^{ - // Impression could not be tracked. Retry the postback later. - self.impressionStatusLabel.text = [NSString stringWithFormat: @"Impression failed to track with error code %ld", errorCode]; - }); -} - -#pragma mark - Native Ad Load Delegate - -- (void)nativeAdService:(ALNativeAdService *)service didLoadAds:(NSArray *)ads -{ - [self logCallback: __PRETTY_FUNCTION__]; - - // Callbacks may not happen on main queue - dispatch_async(dispatch_get_main_queue(), ^{ - self.nativeAd = [ads firstObject]; - self.precacheButton.enabled = YES; - }); -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToLoadAdsWithError:(NSInteger)code -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -#pragma mark - Native Ad Precache Delegate - -- (void)nativeAdService:(ALNativeAdService *)service didPrecacheImagesForAd:(ALNativeAd *)ad -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)nativeAdService:(ALNativeAdService *)service didPrecacheVideoForAd:(ALNativeAd *)ad -{ - // This delegate method will get called whether an ad actually has a video to precache or not - [self logCallback: __PRETTY_FUNCTION__]; - - // Callbacks may not happen on main queue - dispatch_async(dispatch_get_main_queue(), ^{ - self.cachedNativeAd = ad; - self.showButton.enabled = YES; - self.precacheButton.enabled = NO; - }); -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToPrecacheImagesForAd:(ALNativeAd *)ad withError:(NSInteger)errorCode -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToPrecacheVideoForAd:(ALNativeAd *)ad withError:(NSInteger)errorCode -{ - [self logCallback: __PRETTY_FUNCTION__]; -} - -#pragma mark - Utility - -- (void)setUIElementsHidden:(BOOL)hidden -{ - self.appIcon.hidden = hidden; - self.titleLabel.hidden = hidden; - self.rating.hidden = hidden; - self.descriptionLabel.hidden = hidden; - self.mediaView.hidden = hidden; - self.ctaButton.hidden = hidden; -} - -@end diff --git a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/Supporting Files/Base.lproj/Main.storyboard b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/Supporting Files/Base.lproj/Main.storyboard index 4244ff13b9..07d505eac2 100644 --- a/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/Supporting Files/Base.lproj/Main.storyboard +++ b/AppLovin MAX Demo App - ObjC/AppLovin MAX Demo App - ObjC/Supporting Files/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -100,48 +100,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -165,7 +125,7 @@ - + @@ -185,7 +145,7 @@ - + @@ -205,7 +165,7 @@ - + @@ -225,7 +185,7 @@ - + @@ -245,7 +205,7 @@ - + @@ -266,7 +226,7 @@ - + @@ -705,72 +665,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -780,11 +674,11 @@ - + - + @@ -879,7 +773,7 @@ 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 k!GXc@q+qV)8;AN&;02><{9 diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_play.png b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_play.png deleted file mode 100644 index 2acb854f1827a12957418f1e22aa868459f37d2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10380 zcmbVyWn5Hm*X|w|y1TojJEXfokW!E#r5S0E7)rWJ5$RAt7zHI17#cx9QbdGNx}|G` zvw5E9|D5yT{k;j0RRO23jy$P!5>?{ zm#*LsLx7fbfVr=0K(K?K3!vug>*&I+=k4&&#mvRQIrPzI7exTT_IJN)9bj!_sNm%5 zE#h#~MkK@=4)z8BMU@b^gOjIA0K22hLw6q~&b^PFob2w-N}N{GMq);A4Hq|e-7r5F z^DyJPPGO!-^3I$p%Iu0E3g7_VE&&egA>Lj-{t6*Voc|hE0sMdSSd^3fUrho$l{o(` zl(ms5yN0iy3%j(4w6K$yxD>mryok88xRji@5W9q!xTL6Pxfx&;Kl6+}gYgM&qaB}IJw9*T;~%gc+3Nr*~F2!kzz{X=~M z972SB{JH)aLDR+G$zg6&t8yWp~U?2bg7z#9*Xov$` zR9r+%)Z6<;uYa}n4={82zheB4t^MzY!d*noT>O0l{hUC5xN`l|8MNL1KG97>P#Ogj zKX=e64qlqRPJ!MoJ^^}~N}S*u5odR21z8y>M@eTFS7Apn2}fZm2PX$%IcFJXVM!@R zM;T{H2S?Df|BUlL_16#+)6$k#lhqPalMxr!l9JZ|4X7?DBPOLSEv6+a^G{zrAO8Rc zA19Z8=5`0?{!d?-|Fy4zhM$W=fUnEO}=ghpX_X zoM)oqZT)_Cgbb6@c{T^zU3nRkAn~@bvst$YZ{ZW-nr?jhRKB=S+(S~rX|`}G?|nTp zN7N&yT%&jybrLxgNnETPF+}mMpZJS~m=3ZSrc`|CE{IVw7o+Mbyh@cqxEEjAke!g% z5!czCeLq@z3~TN>i0?ERq{gNMY+(4S1Tyqq>`xQWe|%u=`%1|HcC(@SP;u3d1o@DB z(tNy=xCbl*z_@a1*OQnutV61z1-dV`uBUg1@_7=~7-!{?caZ}}$$CKIA`-$xa)LW+ zjm(1C(S$Wf!{|`iU6Bw2NNuHvDpu(ScqDYzx$6m0r#aVCPFrXS)iz}n2{)h*#rsu_ zPs-N2kL}-^k{k0E8l;ZYInvbymXoDt_qtZ`jeQL>D($539pUubkCC^+xVZr{JiN{7 zm=T(elji#_F1}_KtN#$*YVL+YY70c8D`~CZ%u!I1+Y)$1E>9soucpyyORb70U5dA+V88*R-icB_TA% z%qr$^XdRsvaIk8JY>?|v5K(KQ6Eb~AzfBK5>sE(jDwZ*td`K#@XuBdz^1IhESg7d- zi!q^hu6Y6mrIDwo`fNbAAfrop&8>MsvgzJV&g<8=NbYHA#aGwY*Hc8{%^V%tK#ZN7 zoHV*p|J1a$hSD)HF;NK$3Ytq{Sd>N{!k$UkYMqsE0~6hZUJaRtwNK{e?s==JscGH0 zb0^Tj!67g*GSbM$$7ket>zgO~^q7oQ@v9!m)$Y%a!H*t25k4dciq{5b$SJ>Ozs}4WAt&_p}_kCHJ8qKi8$d@m~H6|rKvcbFa9amRZ zqxt#y`urswWZMzxq6XSnrF`&j3&BOHM1kl6WdQ+#7ahQMhh?orpc*a}6;*6zX6Azb z>X(h%4&Bg)&vbBW;+u{r2oSrE*3J%>oaH;CcIMu{!^R_B_FnAxOB#O8B>x-7%gZaZ zySv*~T|?tC^zq~2&v*14VJuB`dLr*ak)6nyLcc6HGfxa9-t z;_>;#?ezBc_D9anm3W#s3!vukbLzbDfO zihxPsf}-_#00AN4yR`Il)?X_tJk#o8a$;w+v!RrTMO0{{trkz~xE=mJn~s)N)f>By zGR<$_W*vkxAh6?^WW4?m5)m;gUJAp?3FZ)`gw+cE8@3%4JG zCh+j%SOFY;0@0{w@#5lQv)j0&8KMI&J>_-uG=f;DJ9A2Aeph@Z#ftH8ajNeA5WmQk zN58t`Z-qBsp6-oB-g@&&l$q%4p0@x%dx)Pk#Dt1CFDolcN}&@SH61PvmyYq2Ssg1W z`QSEQUQ%0I%fubvZf&t{{=O1uvA^i7JXrRfZ`nux3|>^yXzggDmvBy80VBpDJUF;H zZ;+>q%Xo>NO|SnRfJE?(M(I0}oF-B6`HU7TU78sgk-S+o=a`w9(SG~(EmurT%zPzf zYD^lMo|e(&8CL0J6d%so05g24Kh3Jz@R?t9k$pSNAs>xK`-9uZC~pu66dR_})C=c= z*#$VHy(I9ID(qhwF1S9}A7HcRqhrsUuC-c2{Efk@)cRnqfY?z{QerVPGxxGKbYtr!Ji>^m+oVG@lXfu8zKfAkKJzV5zsT}8=v=WA2F2hz z%LZLGjlzCu0P^+N9q|%Yxrp;P0;=rfloY0y_o;UJK7anqEgy|~D=Jyf#pmYZ!%GhT;J`4en!c#UpF#~wcsiOP-`Uw2 z#R+Cdo85)>A7YPw_fC>)Stf-rgy;^*w5CD~=?tmiO>B4=_Na<%yEx;P&_h?HlUEZH zX5uDp{pIC*x=J{x_K^^&>{xme{I&DN@WYXi!cDHDu0#s1I^!1#$N7m{(A^jk^chc2 zb}Ar~w1R2rCZjvgJfyn#{kt#4;&5&3nvKGWSRvXw(}NIkSxA?%e;4k34F;L92|^Y1 zMa-7{^{vaZrHrwpmSC8`ERz`(AoPh|c!uhGle@Wxp`jr~ph*l4m=%M|D=He2rxa-? zzt;;cPEXUL^xr~(=A+;B%A5I6PfAKkZIdFoaf@DE^qv_xV9T8)h;b&QJq+1-|LwQC zfhY&AjEs!-t5>hoz_jW}eIkT&2;G|U(6Wo8h@$B^f165YdBCy8*IN!=kNQ&?X7T#0 zePi;PZrf?sHDaL!<2Vhwu!;=|M2xB>z#Xm%HD#ft4YI6MQ!{LD@1q8avSE=2LksPX z8_8G{0!rH0IB-t3znc^P71xQYPHQzbCJJ&T227;&93lp+o7skMn;$<=*GCKVJ$v>{ zjgy9sbxP13&$2aODr}|`0S3lAa5=pCxUz1&fph2E_WXqu!7zn9Oc7DjlnPG(@ z+&Am(K1yi1g{5`i!0@-`ujk%-x_Ex8AF=RH0QU`gb>z7$pfIE9>+9?9C%!>NL6MbH zP%seYKgXSJ|GYvLaz-`$u?t59gd3kg1$8T~aw!K1-&kHsDJo*J@rmNDDn%jd*fI$# zFPK##F{>MsHEiG-$yH4+l6zFHsH}V?v*fyn?LU0J%g*jT+Gk z`!d8?keho~M_YTh0GOFa{FGJC^!UW^Y(V8oO&~fBMdC&OU0;|mWcmR>%(q7% zAHN{L&mXe9yUTjIOrUk$LWkaIUflimEQ(7~vN89BQWuYU8H2$zv#_wdVUV^N-LLAE zW=R98-}yyy^YX4T%BxgC^>OI%{{G#IdT1jD%~-p%duWDet*dYP^yw4ru&}u-sPbp8 zg-_=vJqcu63^MXH6<7#|A!kdgP%t$yNgXt>!SjJ~ppYjMkmG`%{rSa2{JaRub({in zrbM43`E_%1vuSJQ&2Ysor~xCQqquh5&H4>#uU7b8fF|(t%_Zo_vmG$}2nUkr6HEcD z@~m`p1AZB(q7y=ZR)*LyFmQZ){OFiYfalM_0qARJ(Dv-390&iL_}q>WEJP@FPMS)~ z;x)LyX{LC3^$6gikSgf5o~~}lAo2l1;52(*vB#1+mH>~GxwHY)_w_QmE4HozAwvLM zi9GG2nVy;P0E4x$c~mat%WM!((TL68N}Y}&p5p|#c25Y%LZ8n7O&qEB#lq$A=o zS)3+68Gwyv{1U3?78id@{!QDQt~6J51fAvhaI{FkacZ7lYBp1ytEF2n=ebU4Y#M(54pKRMu0{R4rv~t0_whR^3xGJK+ z*<^v%Fo<1*Dy-gY=fbWq=j|Kr0fVyE5zOP?ND7G%eBb&Tdlj&0uf7ZpzAU?G1WZ7p z^aRr9wzmRe1lNsViL)VXuCLm($z?c+;Dyi+miKLMZzmij3-GW% z00H7Cm$ng!hX}wbbnjEx@g`ST-;J1j!oq2J8AqNXK)ujC#m6T?1V9xum$Iq5)qlzNFh9+`RYSTTr6SlDLSp*P#8SVrFfvi=}F+&n|5LNCN_Q z9yg1OR9?A;RzW8YXmqF%#X|RnMn-rb?EE}#*rB1Jb)1M|e!y@PXo>u*KmdTds42V( zuMxi#yo%f8)CAO?_XAR?g^pAZxA${=V9^+2`184&i9Y=NU(=(%$@X6ZugPillrRdW_RwW z{YzM-5^)WP*mSU9U|?VXmRMP1E^OgbXtD_b{duYYAtI^cewUi+W=CATSxo!mQ{&mj zhZ*JOSbrF_2mmc0PQ)B577Ti~6nJ1q<5CXUSf)_W0$-IG85yn5h^qilc}g0s@`7g?9|jdbpfMxZz%%_A>s)Xk;%2O zvC%pDRD8+n!Gq%8qlHii?3W~?1_u`UNC?oLvLj%5a%sY`HpZwNe&)`jprTRY?v@N3 zMMzRZ$f*wu#vV%9S!)8TtE+Y|w0$#=36q z57(V8wSlp~@D&pk*px*mwY&6L0zcrw4M5{D6J3LYgQ)KA7_BMWCjy8ClkGl88d$zh z$^mK|QA}_+T&(LaDRJQ~S!W6eyNHO0>(u+C4{;bGS|QzwCARCQ_0t{}t)Iree}87t zYuj%Kd}?nOe)*WHf$%(mgz2PW?jV99BHoA)5fT=b4S>QoLqPu;XdC4@J&4TEG5|qN z{?v3*zIvo|`a$!P+FHTdj1?tn#1El+o0BzUT0k!mM<=7s`42H%)TUD?lQ|+hwVOJ? z92EUs|L4z1@eQ!F^xOPE3!UoTuY#166q5FPG1}+%@lpy=0~3X6=D}Tzg)+?RN+e>k zva;Yp6RU#UB0G1_?F?kU_0I7w5&GGfBo*L%v_AfGoyL67#AJCTl~Fo5F9Q>W1<%n+ z0SOLnfck*y4RA+7kS%oe&}i6S(xyr7hJy&}+a$ahD&p+y3`vRjvPz-Km_i#75%G9J zusX9OGcKc2mJXqaycf|tTcJbd&xl`{S>pB#jE46m=j88`1l6_z=pq{b?Q$olR~IRmapI=+|M$k7AwY_nPKZ+%TA77 z=g}NY-i!Q+URxU&lD+!&?YR!HX5Ex3h!qhY-ZrrX%5g>#l5Pnuao6{@SGERNnM30A z_?oU`#XG7EMe32iWnD)K`-b>l+tWf6ac__PCd9(V)&rcG4<`9LcM0(E;m&8rzFzLc zfFADQL-O4t8A(aWx`u`t^H>+!gUN2zpHA-X?o!T!)* zC{0zr0x5xqW`hlEtD`S|q>SU1R%c)gaMK8y!cRD-;J~&t*m3_kZ^>P#bxuA|=5`*+y9HBy+PblB>c-(Twod14_5CkG*?Tv+vjK@C^b}$P(8jz2@)wrw@FBSP@82@ zYuWm=u<)IN#GX!l{O`^u-Xt_feQZ~M5+bK)ZpPr?;9w*9c&=wzasv`ujMY zO{Mr2uK8fYEwH%sx;)+*c&%<3@fZh9F>6As!9lhO?&8`cuwrbyy0Ch$17t?MYiqk< zVZQ(P!DQYHicNB~F*y)0QK{!c{5<@XXfrQxO{vtz@W?2ju1f=rYm zAwC(|skE$Y4FiPmoCcDQx%a{Andp*hr^m3pM{N$vue0fBL!heZhLfNRWFb7yLsc6+ z4-Y$9?|MhAOgcZXX$E-M=s<4BoOO_;(f*mB9x1=Hv*XKhh8Pw(b2^EcRIN zY5p_|+VU4j?GRUsXmWHGMJsO)z=uU+Dz1LaT@?J_0!~q+Z^J`wIGzDJ^Qkoc&w(*9Vtsv`qDd}MJ+d_#$G4)qTw9gSm67?wH=Q4X z00VQ6cXwhzfmH?xlg!I7)lBus^S3U;v~04n%|5Bm`@B29Ur+8~FM)^YUV=L5GovsZk{8Ich&8 z>PQ3_j6y~t(fFh#kr%H#Hu3spy~n4<8(kF4t)NM!+wH+gL;ZsRA7 zH0{F>kRw#NDXfy)7&)Z-)0iImZ%(~}QFL5c|5;+0!9sAH+$}|%C ztt>5N%&fSrojg5%tbp~sn)PS>xYfPbUs$a}qZqEXS^tb5ao0lqL^r$DG=pZ&19<>^ADU6}B>^Z7POFxd)^W|QF4B2z^hJkn$9c8&v0wvYXS`3P zQV@b756Ah|y-^`#{oZ5RRO}(h01$C^oRyw?Xeb!@d39R!hyl!(Y^ z)D0K(>LXjamHXRBXPY^ zQ-VcLcM@J4Tf{oLITc9wRZ|pcXdL$*Vg#Z~MaJ7f+pj(b@5z|b@hT*P{oVci{Ma!~ zwEGf~I6W6wRc%)Z$I_Y6Db%zn=fB~0L1t#zojEx<1c6TF6{FXOV=9*^+n7Pl2)RyW zoKgXrM2f>#p&=mwc*n)M8^CxLlC2YS!;8>W{jAUUYQHF;O0~+|>83UnuK)r@i|FX+ z8gNq2SDsW2Sa=w*wY}-uf~vuS7-dp%_K9yQ37-CaZ{)n$@GNkIlJ zxlMMQQEoc;;%GyaK(15!&x^1KnQljM>|Kj1&274rM(m`dBwwTFGH>_-{mXgaS!AP! zDT;H8y(MzE!&^3QTrW)0RqRdg!e5}WxOA{A8y@^DXuCbmY`c&mh|w%w^Zk9FrWcIyh0qA0bDnDX71y@eyDAt;CDA4tH*joR~ zJwlUjrn1sJ(?RmbXiaI$1BvNva`gjg18EQP^mw9E|7ni z!UB={HMBn&+g>>nTK}LuEDFR6boI8aW=8egDoAHp)+vDrn}~*TdM|40vZr($I1tq* za7sbJW zoY56#MtFthW@cvXU_AVi#w5EcDwn(6Lw6Xf57?H0((8%G|?YBY?b! z1r@D!zcpY6JVu*gQwUh^Un_|!zHe)5XpwYVtwcG(@LRpz76T>aZ+CBR;hMSh6?N*z zdP8&qco0?i3qXWvm#1bFhKx0KIuj!3HFmP6_>iP&_i$Ppu$35_53iC)|3LGW-2IL&LrILpU8L ztl+UuW8Q|hGrmJq8MBC`F%|;-o0OUUsKAqNK%jSddHExF5`c4gvLk4DIjS*VChNPP zIAGK0dJKYsx}4scg9kXIM&GqvuL8L z+k!W)_Q=EIb-4_?gI*9kBmsc{1~@dH%szkmlwM$Y=4&+a>41X#gHJ^`z%#-RB{{lj zYIdMo&2TtP!@xE14umH8#VSz`ERPA09g(J{nLoE0Iu|C##>P5=_ZIYpK0cAgAXC4Q z`L#n@iGbfcsYGXfgw^lfndRi=S>)&B9P$eb?@-|PRDevfMN<18e7aR)HsyJbsh4+t zqK6mWL|tF~3{y213!!2fps~5YBW-igG3JW=J*wS5w&-I$FZO$jcl291st5oH>TPzugXqe* z-zY7m5KH?f**-(2(V~Q7oZ)Fy=Wc%LcQpMm0__a?AH{jJfsrno7+=)7s%beFhVVn? z(rGzArAB-wYOf2|k5cYwZYB#}d6uE)S$Yo@Df}Yr-^+E*aUxbfb?uwWYrI^fLeU`eU;-W=A8F)u!0W!oNa7fD z4ZXas&A){0`D5^-k{Q_$_qY(NXxb$eB74B;fWQJ_QTQPyV)V1ymIwhNa)0&AB5rd1 z4nOVoc8l*a6;d&bdD94T@3+G2M|C-RoeYgfut(n=nC+3VMJ1dFD+z6UioY9o1{v!n zVlR)!CM(z>>-bct8F+ZSmAZ0SWKrhCi?RVVtWqMl1^q6R=$Bh_+1;+Lc5K-5u6G-c zGJ$n$9i#=b{q-9rB~m>E&$ma>-(--KVa(is5Q=LU34F$5?nEZS$ex_qNB6}{PcE@T z$cfn0@K!W#U;+he+zJMllOKN(HW3)lzJq`JOO#x*E|TvL;z z_d1@8t{A5AIjluYug=KMT5C;Y*1O9`#{c3z^=J-2et}oObL!2DYYk}~@K^Ef`XU#} z+kN-!TIw&uIR4Dn?J+sR48d*qLi@kJ0E+2Z{N<)^JcChz-~z?mWWOFZ&tBhrAE>8g KtXZ!Pi}^narUn53 diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_replay.png b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_replay.png deleted file mode 100644 index 2ed3bd3bfef802b7e2c14abd2c16186ae5f67744..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15399 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 ZmADu$o@n+~T)(=jEUzy2?xAVe{{yXJ(ii{$ diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_unmuted.png b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Assets/applovin_card_unmuted.png deleted file mode 100644 index 773cdb07fe2297e3cc7993e849795b1c80a44c4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5483 zcmbVPc|4Tu*S}^=A=yTYtqdY9!(fICW0%NQX^|qv43lAG#x6!FDN7~EWNSl7Od>m} zCr@dptWlO06|y{2wlMECJx|a3{_*?#{&?q~IoExk<$J#8ocr8&qKlKQ$IDAd(pY+Fn8(?eKsgXbpggS$L2a*`LC~cvF07fh4twng%rt&4;A6pWujd z46>s5(RM@zQ}#qUxsoIO$woeEW~LaEa3XXNKw)`d!UO1mOky}m?U!F7l!cdd)G)tP zSpFonzd;>vbir6Lf+-k+HUUe<>EbblM%uarUHmrPtr$I=uD%XVUq@FTtE)%E84+~} zn16n1Fj}w=mAKn_`#-VZiKOPoVg(U(bi%^Iw8QkZ8Nt3fx<*DuIygNYJv}Vcz%nBO zSzh7TK&JX{57rbWIhYp2qA>z7LXTeFj1U${4I=$Jg@7PO$A29MGXEh8Ql=B`6{Mr9 zjnfGT5a#tuo5|Wu`Cl0SQJd)+5k%41O<^)Zg2}KRRQ2D+kh}jLNT>+W5S@c*uqa-1 zYX&(afD*{EvnHv*JK8=pAEJ*w*^si0>W!u7;qn3_co$X4aqpe z-+um+y(P}b$k1lHjSbGiKv&lWZ)61twA44i;kOfTHiibjZS4Y?EU!Q^<#%ivjQx+T z^?$V`S_M0NV@*1Rrk$AFLi#&k!bWh{qav;k>XEs=g8IC@(`J1B%)|_CEh#@^m05 z9bu>ZpU(Mx3AUq9{C5uE;onK31j6wNhI8^BH7o~!Y>J(=g=={4Sa!rq&vu38+%x!1 zvUXz@7tR-l9=(mdT&Q>=|Bhs*m#ZM}R`zZdw{!PS+R0bDmUnVq_gWUAjmz_Q?L6TU zb>14i>%zy?jNE3U3H+Z|Yx^d0KELJ9y@<9gNc(6yvlR20Z#>gq#_|sgTm!VyK2@TC z7|7ckc}#qv)FcCJ9#-N65cYU$`uBglj{#ZHIER=33essDKU*1^}4E5XQ*m3hUrB~?3_3B&8O^+`bM z+-kzlqtjg`cN7XDGFwi7ysg##6{+0)iH3e2zYwNky_bsTisJX5WdqFpbgDPvbCp|C z_GmeW7X2NeDU$wfHWfRW)%HqR)$6+|auB`h-E7U;`RoBlW*qfFz9MsH^e zwJ=3Tow~-({xX=Zo~+R&$^7!$-J|p+_3x`DjUKD-CH#^X$<9Y4PyoNA$4x&Qu=|yV z5MZ(Xo~CKfkSEjHrF&Bw(j6admGFrEpprJI9O+-tMZfXpW`3P~--C}c94ZRr#LhKu zFfB;O8}I0mXDxD$dsLXr*>I#~LHM`n)MKm^&-0~+x}7*}-5;4z_RM;!DiWm5ERdCR zN=Pn!yUGfv*^1FI&N~l8(%~KF{Y5{bM$^gBy{bJ1Vyec}@o03|uf;k$375clwb+*HYdv`q<=I z8N{V`v&=Q-5(c&d%lki8+?@HwDcZC4(T>LZO0nz0t(#;H_3;@N+e7-!4=oDWGES9z zps>-4nVMx_Oxn?OMHFTJpOkF%OtB=f^>dv;~$Ze>Noq5sAxuM~(X}eI>a`T!u z8&NSyQfcYdFu^xuUH=((gixhT&(MBwuPxz6r?L==i{u2Y^=0i)VZJOUSr(eyNo#cD zD5M-ETDFTIUd~=qr1v*wzW24~79X#a79tDj>5F6H`Pm(0k@$T!kc`5V3<6nWrK%I} zGhS2(%k>;qJGeaUAl>Nu-!4B%iStEGj?}ROg_(4E*RgL)jT~_1Q&29Fp4X?Wo?KpC zV;)_rFnc;a{gkZvNhN`_-$JQ;*KF*TuQM}cpPq!-3ghJX5)6rjAAqB?Fp-fe)w39l z<9Kz5+Dvr%(&XSBcgNP|r^^m){knfuuR9TEEe{hYqB@Ef^)J~s)r=9(46fr568%fx zoTyQQ)2)41eW>_3jblOBmK(KUaop->#Z1&WNXl)6RT@Xi-bVVyXlH2DuP&`ag<8WZ zy)Eryzr#0Nc9NpoB?Z{U9Dc7@e-^4&y*4&g@%v(5DM_szHWN=3EaL@1gl!7$C_bI{ za;5*nIE##(y$H)FRTy==CweBg{Bz6LnGF1lrb+!b(>g`S>*ti?X40L}&P3gQlI-+W zOea!p+JUk`*np=FpRYa};>_LQ;ZH0Z-~IsAhY?MWV8CC5(oI59_G zqe>+QH2%C)j^F6#wARdj`eB#EY{GCJs(HOU<0|#i5`20;TaJDz9_|}$X&116ULO=1 zR@`fhY4v~Lc47ttpJ7LeJ_K?sbTE5$Xdx&N@^t-luR~LPihuMTzQc7gBN60{_psip ze_giq0#6oPVjq7M#ym7&ZO88oz7p?fBMUlmtZpW^d&!mV;Jcjo(0lfgr!{av)@^W5 zpMJjR5hx-9I##={dOYeLx0cY3R?b)tR{at7WI|@r7OmW_>GA_Ep%n(M;m!r+q?|96 zRxrjBEw`q2hGKEu4V!rMcS z)RnskHchTWo4Km(qv}8_`GS=HeS%2t&Y-uFGT_ov;(KPnwF0zq8Vvtzy_CQGD-roK zAkUgUXUuRv-*9Qrh%G5L0<*=_C0`V0cXq7OaM75?1UaIB#{J^QoP5n~!$2r=smpu` zbteG0^GH)P;1n>;*%$}%cGNn`_o3zMoO08nfImmhqe$UN0L;#NPh9eN4cY8tp|P06xc9xvOK3zC0AyxX+K8 zCWJ_)jfjFbtG?`qC490?oB?XNv=ij|JDI7_a@cP?_+Vd`c*(Mn+p$eE zohhSzn_eBug-2x9tS_;c_jHkwJ6LHj9jk|ASCh*Y$B!M#t(zas9;{5efr2A|T0YA0*V4gz{nem}n8?ZSL)lH*b)%=O;F9_CfP;C|!ejxuu$?5hy|bnuEu~=ouMhu%g)$^L~x!R zHkQ*_F+P7GeqA*4R>N@P6T;j69J3^F-u&p@s{(yqIwvACx8(xILp+r+vnXBhSqEoO zA0mzm%j5Pev0@XuYox|BX%+Jav)pfHGj`6NP>;Klxu)dX4Ya|XyCM~j+f?DwjF6qF zn9(^V(fG~0)8Wj_TnKI99l>_v_`FgD#$FC-j&#A^Ae@xzJ|Y)0KK3Vk81DeY)*xPt z)JUZTu~KUV(ys=kZH+9IpME~^^I~XYs#p6B=7Z&aWH0xyGFr73?dJ zMX^zN0S7V!T6Th$Z3kpx7vWeV{7gjf%{!}?nVRw((fhV+y0m~p?i(?{Z05!gms-hA~E@_PiAMpdGMfrwmZ}{?Hylm zyGXDLMjT8#5GMGHUcV60v~T+o5V}(Kr#U4Ge#B!h5^u{2aF84s`Bh4SJFO%4KfNlU zcbKI>M`!5Q=5EhMbatO`{Htn*Vx^@X)VoC{|BQt%FyGzK27{kZZC?-l#qH+as+Gzp zz3ge2@PkxR#eF4e0e0kBj}dZ7Uk4u3j$@T>M#qDZjd2p^&3B)MUmM>?XUk6$=DFy7 zbE{Du9tilj~aRiG-*^Zas|O8x`>Qm1(PgdB|d0I?7m09c*y1t?0}ucw>6AcQO!5vAvjF@Rf_9F$B9MX=Sax#p9)ds z56NSeDq3ETQw~+`tq!7CFsZ9+B{~c74a8&0aJe3oy6~xe0aT#`lT~IG?a99ZZww>o`R>-#;Tk2Ex}i znxgYRbw$WJ=@!_Ratrm6%OUk{zZ=ZY&srkK7HHGXv@0?M3Jrx7Yk(5#wW@0?)=bBH^YQF|0 z+_-xoqZM zC;Wo&=uQ)kt7%KeY>}B$*4B5Y01(ILEaUjUFIjqkc9Mta#7y#yocM;vOi!&v0Q47P z|HaaX!owMvx3W!yZR=e!y>!>eLoe&eNodPjsZ{+_n#bi_-MMz?uLq~zYq+ck^%U$_ z=#0IZ3Kzq9b8*Rm&<|Wnwa0sPTj0{Fvvh+y)bRWhTr|r=of+N@X$d{K&mw zCtf&DSz8pz)(dxQdTvr7ZY!4|f-qmqT&uM3ZWny7$Q$mtndQ5|p{2Y#LZWH|TrOWcRvp rywQa~nmc6+z#zyM5n1&@fRYDOzB%VC4))Xo__MQdvc6|| - -NS_ASSUME_NONNULL_BEGIN - -@interface UIView (ALActivityIndicator) - -/** - * Show an activity indicator with a semi-transparent black overlay underneath without fade. - */ -- (void)al_showActivityIndicator; - -/** - * Show an activity indicator with a semi-transparent black overlay underneath with a fade animation option. - */ -- (void)al_showActivityIndicatorAnimated:(BOOL)animated; - -/** - * Hides the activity indicator view without fade. - */ -- (void)al_hideActivityIndicator; - -/** - * Hides the activity indicator view with a fade animation option. - */ -- (void)al_hideActivityIndicatorAnimated:(BOOL)animated; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Categories/UIView+ALActivityIndicator.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Categories/UIView+ALActivityIndicator.m deleted file mode 100644 index a23678f6d8..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Categories/UIView+ALActivityIndicator.m +++ /dev/null @@ -1,88 +0,0 @@ -// -// UIView+ALActivityIndicator.m -// sdk -// -// Created by Thomas So on 5/15/15. -// -// - -#import "UIView+ALActivityIndicator.h" -#import "ALCarouselView+Internal.h" -#import "ALDebugLog.h" - -@implementation UIView(ALActivityIndicator) -static NSString *const kActivityIndicatorKey = @"activityIndicator"; -static NSString *const kActivityIndicatorOverlayKey = @"activityIndicatorOverlay"; - -static const CGFloat kTargetOverlayAlpha = 1.0f; -static const CGFloat kAnimationDuration = 0.35f; - -- (void)al_showActivityIndicator -{ - [self al_showActivityIndicatorAnimated: NO]; -} - -- (void)al_showActivityIndicatorAnimated:(BOOL)animated -{ - UIView *overlay = [self valueForKey: kActivityIndicatorOverlayKey]; - if ( !overlay ) - { - overlay = [[UIView alloc] init]; - overlay.backgroundColor = [UIColor whiteColor]; - overlay.frame = self.bounds; - - ALLog(@"Created overlay with frame: %@", NSStringFromCGRect(overlay.frame)); - - [self setValue: overlay forKey: kActivityIndicatorOverlayKey]; - } - - UIActivityIndicatorView *activityIndicator = [self valueForKey: kActivityIndicatorKey]; - if ( !activityIndicator ) - { - activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray]; - activityIndicator.hidesWhenStopped = YES; - activityIndicator.center = self.center; - - [overlay addSubview: activityIndicator]; - [overlay bringSubviewToFront: activityIndicator]; - - [self setValue: activityIndicator forKey: kActivityIndicatorKey]; - } - - [activityIndicator startAnimating]; - overlay.alpha = animated ? 0.0f : kTargetOverlayAlpha; - - [self addSubview: overlay]; - [self bringSubviewToFront: overlay]; - - if ( animated ) - { - [UIView animateWithDuration: kAnimationDuration animations:^{ - overlay.alpha = kTargetOverlayAlpha; - }]; - } -} - -- (void)al_hideActivityIndicator -{ - [self al_hideActivityIndicatorAnimated: NO]; -} - -- (void)al_hideActivityIndicatorAnimated:(BOOL)animated -{ - UIView *overlay = [self valueForKey: kActivityIndicatorOverlayKey]; - if ( !overlay.superview ) - { - return; - } - - UIActivityIndicatorView *activityIndicator = [self valueForKey: kActivityIndicatorKey]; - [UIView animateWithDuration: animated ? kAnimationDuration : 0.0f animations:^{ - overlay.alpha = 0.0f; - } completion:^(BOOL finished) { - [activityIndicator stopAnimating]; - [overlay removeFromSuperview]; - }]; -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h deleted file mode 100644 index 84cad4d4fd..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Customizable SETTINGS/ALCarouselViewSettings.h +++ /dev/null @@ -1,86 +0,0 @@ -// -// ALCarouselViewSettings.h -// iOS Test App NG -// -// Created by Thomas So on 5/27/15. -// Copyright (c) 2015 AppLovin. All rights reserved. -// - -/** - * This file contains advanced UI configuration for ALCarouselView. - * Sizing and colors can be easily tweaked to your liking here. - */ - -#ifndef iOS_Test_App_NG_ALCarouselViewSettings_h -#define iOS_Test_App_NG_ALCarouselViewSettings_h - -#define kTextColor [UIColor darkTextColor] -#define kReplayTextColor [UIColor whiteColor] -#define kCarouselBackgroundColor [UIColor whiteColor] -#define kCardBackgroundColor [UIColor whiteColor] -#define kCardButtonColor [UIColor colorWithWhite: 0.84f alpha: 1.0f] -#define kVideoViewBackgroundColor [UIColor blackColor] -#define kVideoViewBackgroundWhilePlayingColor [UIColor blackColor] -#define kReplayOverlayBackgroundColor [UIColor blackColor] -#define kButtonHighlightTint [UIColor colorWithWhite: 0.87f alpha: 1.0f] - -// Media controls -static BOOL const kIsAutoplay = YES; -static BOOL const kVideoClicksThrough = YES; -static BOOL const kConfigIsMuted = YES; -static BOOL const kRenderVideoScreenshotAsFallbackImage = YES; - -// Replay overlay controls -static NSString *const kTextReplayVideo = @"Replay Video"; -static NSString *const kTextLearnMore = @"Learn More"; -static CGFloat const kConfigReplayOverlayAlpha = 0.75f; - - - -// Carousel constants -static NSUInteger const kNativeAdsToLoadCount = 3; -static NSString *const kFontFamily = @""; - -// Carousel layout constants -static CGFloat const kCardWidthPercentage = 0.90f; // As percentage of width of screen -static CGFloat const kCardMargin = 5.0f; // The margin on the side of each card. So a margin of 5px would result in a total of 10px separation card-to-card - -// Spring animation constants -static CGFloat const kSpringDuration = 0.3f; -static CGFloat const kDelay = 0.0f; -static CGFloat const kSpringDampeningGoNextCard = 0.9f; -static CGFloat const kSpringDampeningReturnSameCard = 0.7f; -static CGFloat const kInitialSpringVelocity = 0.0f; -static CGFloat const kConfigSwipeThreshold = 40.0f; // The number of pixels that will trigger a swipe event - -// Card layout constants -static CGFloat const kCardPadding = 10.0f; -static CGFloat const kTopMargin = 5.0f; -static CGFloat const kAppIconSize = 40.0f; -static CGFloat const kRatingHeight = 15.0f; -static CGFloat const kStarRatingTopPadding = 0.0f; -static CGFloat const kMaxStarRatingHeight = 15.0f; -static NSUInteger const kStarWidthToHeightMultiplier = 5; -static CGFloat const kDescriptionVerticalMargin = 16.0f; -static CGFloat const kVideoAspectRatio = 1.0f/1.78f; -static CGFloat const kDescriptionTextHeight = 36.0f; -static CGFloat const kCtaMaxHeight = 40.0f; -static CGFloat const kCtaCornerRadius = 3.0f; - -// Card configurations -static BOOL const kConfigEntireCardClickable = YES; -static CGFloat const kFontSizeTitle = 14.0f; -static CGFloat const kFontSizeDescription = 14.0f; -static CGFloat const kFontSizeButton = 18.0f; -static NSUInteger const kDescriptionMaxLines = 2; - -// Media layout constants -static CGFloat const kPadding = 10.0f; -static CGFloat const kMuteButtonPadding = 12.0f; -static CGFloat const kMuteWidth = 20.0f; -static CGFloat const kMuteHeight = 20.0f; -static CGFloat const kMuteButtonMargin = 8.0f; -static CGFloat const kPlayReplayWidth = 40.0f; -static CGFloat const kPlayReplayHeight = 40.0f; - -#endif \ No newline at end of file diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.h deleted file mode 100644 index 399ed62aea..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// ALCarouselCardView.h -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -#import - -#import "ALCarouselMediaView.h" -#import "ALCarouselViewModel.h" -#import "ALCarouselRenderingProtocol.h" - -NS_ASSUME_NONNULL_BEGIN - -@class ALCarouselView; - -/** - * This view is used for paging of the carousel. - */ -@interface ALCarouselCardView : UIView - -/** - * The view containing the ad video or image. - */ -@property (strong, nonatomic) ALCarouselMediaView *mediaView; - -/** - * Initializes a newly allocated card view object with the specified sdk - */ -- (instancetype) initWithSdk:(ALSdk *)sdk; - -/** - * Redirects to the CTA for the given ad. - * - * @param ad The ad with the CTA URL to redirect to. - */ -- (void)handleClickForAd:(ALNativeAd *)ad; - -/** - Call this method when your view is displayed to the user. - Will track an impression. - */ -- (void)trackImpression; - -@property (strong, nonatomic, nullable) UIActivityIndicatorView *activityIndicator; -@property (strong, nonatomic, nullable) UIView *activityIndicatorOverlay; - -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.m deleted file mode 100644 index ebc5c9fb4b..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselCardView.m +++ /dev/null @@ -1,354 +0,0 @@ -// -// ALCarouselCardView.m -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -@import AppLovinSDK; -#import "ALCarouselCardView.h" -#import "ALCarouselCardState.h" -#import "UIView+ALActivityIndicator.h" -#import "ALCarouselViewSettings.h" -#import "ALDebugLog.h" - -@interface ALCarouselCardView() - -@property (weak, nonatomic) ALSdk *sdk; - -@property (strong, nonatomic) ALCarouselCardState *cardState; -@property (strong, nonatomic) ALNativeAd *ad; - -@property (strong, nonatomic) UITapGestureRecognizer *cardTapGesture; -@property (strong, nonatomic) UIView *contentView; -@property (strong, nonatomic) UIView *topBarContainer; -@property (strong, nonatomic) UIImageView *appIcon; -@property (strong, nonatomic) UILabel *titleLabel; -@property (strong, nonatomic) UIImageView *ratingImageView; -@property (strong, nonatomic) UILabel *descriptionLabel; -@property (strong, nonatomic) UIButton *ctaButton; - -@end - -@implementation ALCarouselCardView -static NSString *const TAG = @"ALCarouselCardView"; - -#pragma mark - Initialization - -- (instancetype)initWithSdk:(ALSdk *)sdk -{ - self = [super init]; - if ( self ) - { - [self baseInitWithSdk: sdk]; - } - return self; -} - -- (instancetype)initWithFrame: (CGRect) frame -{ - self = [super initWithFrame: frame]; - if ( self ) - { - [self baseInitWithSdk: [ALSdk shared]]; - } - return self; -} - -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder: aDecoder]; - if ( self ) - { - [self baseInitWithSdk: [ALSdk shared]]; - } - return self; -} - -- (void)baseInitWithSdk:(ALSdk*) sdk -{ - self.sdk = sdk; - - self.backgroundColor = [UIColor clearColor]; - - self.cardTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapCard:)]; - self.cardTapGesture.enabled = kConfigEntireCardClickable; - [self addGestureRecognizer: self.cardTapGesture]; - - self.contentView = [[UIView alloc] init]; - self.contentView.backgroundColor = kCardBackgroundColor; - [self addSubview: self.contentView]; - - self.topBarContainer = [[UIView alloc] init]; - [self.contentView addSubview: self.topBarContainer]; - - self.appIcon = [[UIImageView alloc] init]; - self.appIcon.userInteractionEnabled = YES; - [self.contentView addSubview: self.appIcon]; - - UITapGestureRecognizer *appIconTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapAppIcon:)]; - [self.appIcon addGestureRecognizer: appIconTapGesture]; - - self.titleLabel = [[UILabel alloc] init]; - self.titleLabel.textColor = kTextColor; - [self.topBarContainer addSubview: self.titleLabel]; - - self.ratingImageView = [[UIImageView alloc] init]; - self.ratingImageView.contentMode = UIViewContentModeScaleAspectFit; - [self.topBarContainer addSubview: self.ratingImageView]; - - self.descriptionLabel = [[UILabel alloc] init]; - self.descriptionLabel.textColor = kTextColor; - self.descriptionLabel.numberOfLines = kDescriptionMaxLines; - [self.contentView addSubview: self.descriptionLabel]; - - self.mediaView = [[ALCarouselMediaView alloc] initWithSdk: self.sdk parentView: self]; - [self.contentView addSubview: self.mediaView]; - - self.ctaButton = [[UIButton alloc] init]; - self.ctaButton.layer.masksToBounds = YES; - self.ctaButton.layer.cornerRadius = kCtaCornerRadius; - self.ctaButton.backgroundColor = kCardButtonColor; - [self.ctaButton setTitleColor: kTextColor forState: UIControlStateNormal]; - [self.ctaButton addTarget: self action: @selector(didTapCTAButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.contentView addSubview: self.ctaButton]; - - // Determine label fonts - if ( [[UIFont familyNames] containsObject: kFontFamily] ) - { - self.titleLabel.font = [UIFont fontWithName: kFontFamily size: kFontSizeTitle]; - self.descriptionLabel.font = [UIFont fontWithName: kFontFamily size: kFontSizeDescription]; - self.ctaButton.titleLabel.font = [UIFont fontWithName: kFontFamily size: kFontSizeButton]; - } - else - { - self.titleLabel.font = [UIFont systemFontOfSize: kFontSizeTitle]; - self.descriptionLabel.font = [UIFont systemFontOfSize: kFontSizeDescription]; - self.ctaButton.titleLabel.font = [UIFont systemFontOfSize: kFontSizeButton]; - } -} - -#pragma mark - Action Methods - -- (void)didTapCTAButton:(UIButton *)sender -{ - ALLog(@"Redirecting from cta button click"); - [self handleClickForAd: self.ad]; -} - -- (void)didTapAppIcon:(UITapGestureRecognizer *)tapGesture -{ - ALLog(@"Redirecting from app icon click"); - [self handleClickForAd: self.ad]; -} - -- (void)didTapCard:(UITapGestureRecognizer *)tapGesture -{ - ALLog(@"Redirecting from card click"); - [self handleClickForAd: self.ad]; -} - -#pragma mark - View Management - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - // Layout content view - CGRect contentFrame = CGRectZero; - contentFrame.origin.x = kCardMargin; - contentFrame.size.width = CGRectGetWidth(self.bounds) - (2*kCardMargin); - contentFrame.size.height = CGRectGetHeight(self.bounds); - self.contentView.frame = contentFrame; - - // Layout app icon - self.appIcon.frame = CGRectMake(kCardPadding, kTopMargin, kAppIconSize, kAppIconSize); - - // Layout title - CGRect titleFrame = CGRectZero; - titleFrame.size.width = (CGRectGetWidth(self.contentView.frame) - CGRectGetMaxX(self.appIcon.frame)) - (2*kCardPadding); - titleFrame.size.height = [self.titleLabel sizeThatFits: CGSizeMake(CGRectGetWidth(titleFrame), CGFLOAT_MAX)].height; - self.titleLabel.frame = titleFrame; - - // Layout star rating - const CGFloat ratingWidth = kMaxStarRatingHeight*kStarWidthToHeightMultiplier; - self.ratingImageView.frame = CGRectMake(CGRectGetMinX(titleFrame), CGRectGetMaxY(titleFrame) + kStarRatingTopPadding, ratingWidth, kRatingHeight); - - // Layout top bar - CGRect topBarFrame = CGRectZero; - topBarFrame.origin.x = CGRectGetMaxX(self.appIcon.frame) + kCardPadding; - topBarFrame.size.width = CGRectGetWidth(self.contentView.frame) - (3*kCardPadding) - kAppIconSize; - topBarFrame.size.height = CGRectGetHeight(self.titleLabel.frame) + kRatingHeight; - self.topBarContainer.frame = topBarFrame; - self.topBarContainer.center = CGPointMake(self.topBarContainer.center.x, self.appIcon.center.y); - - // Layout description - CGRect descriptionFrame = CGRectZero; - descriptionFrame.origin.x = kCardPadding; - descriptionFrame.origin.y = CGRectGetMaxY(self.topBarContainer.frame) + kDescriptionVerticalMargin; - descriptionFrame.size.width = CGRectGetWidth(self.contentView.frame) - (2*kCardPadding); - descriptionFrame.size.height = [self.descriptionLabel sizeThatFits: CGSizeMake(CGRectGetWidth(descriptionFrame), CGFLOAT_MAX)].height; - self.descriptionLabel.frame = descriptionFrame; - - // Layout media view - const CGFloat maxHeightPossible = (CGRectGetMaxY(self.frame) - kCardPadding) - (CGRectGetMaxY(self.descriptionLabel.frame) + kCardPadding); - const CGFloat fittedHeight = (CGRectGetWidth(self.frame)) * kVideoAspectRatio; - - CGRect mediaFrame = CGRectZero; - mediaFrame.origin.y = CGRectGetMaxY(self.topBarContainer.frame) + (2*kDescriptionVerticalMargin) + kDescriptionTextHeight; - mediaFrame.size.width = CGRectGetWidth(self.contentView.frame); - mediaFrame.size.height = MIN(maxHeightPossible, fittedHeight); - self.mediaView.frame = mediaFrame; - - // Layout CTA button (center it between bottom of video and bottom of card) - const CGFloat ctaOriginY = CGRectGetMaxY(self.mediaView.frame) + (CGRectGetMaxY(self.contentView.frame) - CGRectGetMaxY(self.mediaView.frame))/2 - kCtaMaxHeight/2; - - // If button will overflow bottom, hide it - BOOL willOverflow = (ctaOriginY + kCtaMaxHeight) > CGRectGetMaxY(self.contentView.frame); - if ( willOverflow ) - { - self.ctaButton.frame = CGRectZero; - self.ctaButton.hidden = YES; - } - else - { - CGRect ctaFrame = CGRectZero; - ctaFrame.origin.y = ctaOriginY; - ctaFrame.size.height = kCtaMaxHeight; - ctaFrame.size.width = (2*kCardPadding) + [self.ctaButton sizeThatFits: CGSizeMake(CGFLOAT_MAX, 0.0f)].width; - ctaFrame.origin.x = CGRectGetWidth(self.contentView.frame) - kCardPadding - CGRectGetWidth(ctaFrame); - - self.ctaButton.frame = ctaFrame; - } - - // Activity Views from category - self.activityIndicatorOverlay.frame = self.bounds; - self.activityIndicator.center = self.activityIndicatorOverlay.center; -} - -#pragma mark - View Rendering - -- (void)renderViewForNativeAd:(ALNativeAd *)ad cardState:(ALCarouselCardState *)cardState -{ - if ( ad ) - { - self.ad = ad; - self.cardState = cardState; - - [self refresh]; - } - else - { - [self clearView]; - } -} - -- (void)refresh -{ - ALLog(@"----------Begin refreshing carousel card view----------"); - - ALNativeAd *ad = self.ad; - - // If there is ad, render - if ( ad ) - { - ALLog(@"Refreshing ad (%@) for card view", ad.adIdNumber); - - self.titleLabel.text = ad.title; - self.descriptionLabel.text = ad.descriptionText; - self.mediaView.hidden = NO; - self.ctaButton.hidden = NO; - [self.ctaButton setTitle: ad.ctaText forState: UIControlStateNormal]; - [self populateStarRating: ad]; - - // If the images are pre-cached, just render them - if ( [ad isImagePrecached] ) - { - ALLog(@"Native ad (%@) is pre-cached. Refreshing image resources", ad.adIdNumber); - -#pragma mark - Populate with appropriate stars asset depending on starRating - self.appIcon.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: ad.iconURL]]; // Local URL - - [self.mediaView renderViewForNativeAd: self.ad cardState: self.cardState]; - - [self al_hideActivityIndicatorAnimated: YES]; - [self setNeedsLayout]; - } - else - { - [self clearView]; - [self al_showActivityIndicator]; - } - } - // There is no slot to render, so clear view - else - { - ALLog(@"Refreshing nil native ad for card view. Clearing view..."); - - [self clearView]; - [self al_hideActivityIndicatorAnimated: YES]; - } - - ALLog(@"----------Finish refreshing carousel card view----------"); -} - -#pragma mark - Utility - -- (void)handleClickForAd:(ALNativeAd *)ad -{ - if ( ad ) - { - [ad launchClickTarget]; - } - else - { - // Something is wrong, trying to redirect when card view does not have a native ad (like when ad is still loading) - ALLog(@"Attempting to open CTA URL with a nil native ad"); - } -} - -- (void)trackImpression -{ - if ( self.ad && self.cardState ) - { - ALLog(@"Handling displaying of native ad (%@)", self.ad.adIdNumber); - - if ( !self.cardState.impressionTracked ) - { - self.cardState.impressionTracked = YES; - ALLog(@"Tracking impression for ad (%@)", self.ad.adIdNumber); - [self.ad trackImpression]; - } - } - else - { - ALLog(@"Attempting to handle a nil slot or nil card state being displayed"); - } -} - -- (void)populateStarRating:(ALNativeAd*) ad -{ - NSString* filename = [NSString stringWithFormat: @"Star_Sprite_%@", ad.starRating.stringValue]; - UIImage* starRating = [UIImage imageNamed: filename]; - self.ratingImageView.image = starRating; -} - -- (void)clearView -{ - self.titleLabel.text = @""; - self.descriptionLabel.text = @""; - self.ratingImageView.image = nil; - self.appIcon.image = nil; - - self.ctaButton.hidden = YES; - [self.ctaButton setTitle: @"" forState: UIControlStateNormal]; - - self.mediaView.hidden = YES; - - // Reset State - self.cardState = nil; - self.ad = nil; -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.h deleted file mode 100644 index bfb300920e..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// ALCarouselMediaView.h -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -#import - -#import "ALCarouselViewModel.h" -#import "ALCarouselRenderingProtocol.h" - -@class ALCarouselCardView; - -NS_ASSUME_NONNULL_BEGIN - -/** - * This view is used to store the ad's media. - */ -@interface ALCarouselMediaView : UIView - -/** - * Saves the current video's states and clears it. This is for when moving a slot out of the middle card. - */ -- (void)setInactive; - -/** - * Initializes a newly allocated media view object with the specified sdk and parent card view. - */ -- (instancetype)initWithSdk:(ALSdk *)sdk parentView:(ALCarouselCardView *)parentView; -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.m deleted file mode 100644 index a3eae4be75..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselMediaView.m +++ /dev/null @@ -1,599 +0,0 @@ -// -// ALCarouselMediaView.m -// sdk -// -// Created by Thomas So on 4/20/15. -// -// - -@import AppLovinSDK; -#import "ALCarouselMediaView.h" -#import "ALCarouselCardState.h" -#import "ALCarouselReplayOverlayView.h" -#import "ALCarouselCardView.h" -#import "ALCarouselViewSettings.h" -#import "ALDebugLog.h" -#import "ALNativeAdVideoPlayer.h" -#import "ALNativeAdVideoView.h" - -@interface ALCarouselMediaView() - -@property (weak, nonatomic) ALSdk *sdk; - -@property (strong, nonatomic) ALCarouselCardView *cardView; -@property (strong, nonatomic) ALCarouselCardState *cardState; -@property (strong, nonatomic) ALNativeAd *ad; - -@property (strong, nonatomic) UIImageView *adImageView; - -@property (strong, nonatomic) ALNativeAdVideoPlayer *videoPlayer; -@property (weak, nonatomic) ALNativeAdVideoView *videoView; -@property (strong, nonatomic) UIButton *muteButton; -@property (strong, nonatomic) UIButton *playButton; -@property (strong, nonatomic) ALCarouselReplayOverlayView *replayOverlayView; - -@end - -@implementation ALCarouselMediaView -static NSString *const TAG = @"ALCarouselMediaView"; - -#pragma mark - Initialization Methods - -- (instancetype)initWithCoder:(NSCoder *)coder -{ - self = [super initWithCoder:coder]; - if (self) - { - self.sdk = [ALSdk shared]; - [self setup]; - } - return self; -} - -- (instancetype)initWithSdk:(ALSdk *)sdk parentView:(ALCarouselCardView *)parentView; -{ - self = [super init]; - if ( self ) - { - self.sdk = sdk; - self.cardView = parentView; - [self setup]; - } - return self; -} - -- (void)setup -{ - self.backgroundColor = kVideoViewBackgroundColor; - - self.adImageView = [[UIImageView alloc] init]; - self.adImageView.userInteractionEnabled = NO; - self.adImageView.backgroundColor = [UIColor clearColor]; - - UITapGestureRecognizer *adImageTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapAdImage:)]; - [self.adImageView addGestureRecognizer: adImageTapGesture]; - - if ( self.replayOverlayView ) - { - [self.replayOverlayView removeFromSuperview]; - } - - self.replayOverlayView = [[ALCarouselReplayOverlayView alloc] initWithParentView: self]; - self.replayOverlayView.alpha = 0.0f; - self.replayOverlayView.userInteractionEnabled = YES; - [self.replayOverlayView.replayIconButton addTarget: self action: @selector(didTapReplayButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.replayOverlayView.replayButton addTarget: self action: @selector(didTapReplayButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.replayOverlayView.learnMoreIconButton addTarget: self action: @selector(didTapLearnMoreButton:) forControlEvents: UIControlEventTouchUpInside]; - [self.replayOverlayView.learnMoreButton addTarget: self action: @selector(didTapLearnMoreButton:) forControlEvents: UIControlEventTouchUpInside]; - - [self addSubview: self.adImageView]; - [self addSubview: self.replayOverlayView]; -} - -#pragma mark - App Notifications - -- (void)appPaused:(NSNotification *)notification -{ - [self deactivateIfNeeded]; -} - -- (void)appResumed:(NSNotification *)notification -{ - [self reactivateIfNeeded]; -} - -#pragma mark - View Management - -- (void)willMoveToWindow:(UIWindow *)newWindow -{ - [super willMoveToWindow: newWindow]; - - // Will be moved into a window - if ( newWindow ) - { - [self reactivateIfNeeded]; - - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appPaused:) name: UIApplicationDidEnterBackgroundNotification object: nil]; - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(appResumed:) name: UIApplicationDidBecomeActiveNotification object: nil]; - } - // Will be removed from window - else - { - [self deactivateIfNeeded]; - - [[NSNotificationCenter defaultCenter] removeObserver: self]; - } -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - self.videoView.frame = self.bounds; - - const CGFloat muteButtonWidth = kMuteWidth + kMuteButtonPadding; - const CGFloat muteButtonHeight = kMuteHeight + kMuteButtonPadding; - - CGRect muteFrame = CGRectZero; - muteFrame.origin.x = kMuteButtonMargin; - muteFrame.origin.y = CGRectGetMaxY(self.videoView.frame) - muteButtonHeight - kMuteButtonMargin; - muteFrame.size.width = muteButtonWidth; - muteFrame.size.height = muteButtonHeight; - self.muteButton.frame = muteFrame; - self.muteButton.imageEdgeInsets = UIEdgeInsetsMake(kMuteButtonPadding, 0.0f, 0.0f, kMuteButtonPadding); - - self.playButton.frame = CGRectMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds), kPlayReplayWidth, kPlayReplayHeight); - self.playButton.center = self.videoView.center; - - self.replayOverlayView.frame = self.bounds; - self.adImageView.frame = self.cardState.screenshot ? self.cardState.videoRect : self.bounds; -} - -// Entry points -- (void)renderViewForNativeAd:(ALNativeAd *)ad -{ - ALCarouselCardState *cardState = [ALCarouselCardState cardStateForSingleCard]; - [self renderViewForNativeAd: ad cardState: cardState]; -} - -- (void)renderViewForNativeAd:(ALNativeAd *)ad cardState:(ALCarouselCardState *)cardState -{ - if ( ad ) - { - self.ad = ad; - self.cardState = cardState; - [self createVideoPlayerIfNeeded]; - [self refresh]; - } - else - { - [self clearView]; - } -} - -- (void)refresh -{ - const ALNativeAd *ad = self.ad; - if ( ad ) - { - // If we get to this point, ad image is pre-cached - ALLog(@"Begin refresh media view for slot ID: %@ %@", ad.adIdNumber, ad.title); - - self.adImageView.userInteractionEnabled = YES; - - // Populate ad image behind replay overlay - if ( self.cardState.screenshot && !CGRectIsEmpty(self.cardState.videoRect) ) - { - // If this card has a video screenshot rendered, set that as the ad image - self.adImageView.image = self.cardState.screenshot; - self.adImageView.frame = self.cardState.videoRect; - } - else - { - // Else, just set the ad image to the default one - self.adImageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: ad.imageURL]]; - self.adImageView.frame = self.bounds; - } - - // If the replay overlay is supposed to be visible, show it and hide the video controls - if ( self.cardState.replayOverlayVisible ) - { - self.replayOverlayView.alpha = 1.0f; - self.playButton.alpha = 0.0f; - self.muteButton.alpha = 0.0f; - } - // Else, hide the replay overlay. Visibility of video controls will be determined if autoplay is on/off - else - { - self.replayOverlayView.alpha = 0.0f; - } - - // If this is the middle/single card, we give it special treatment - if ( self.cardState.currentlyActive ) - { - // If the video is pre-cached or we should stream - if ( [ad isVideoPrecached] ) - { - // Autoplay if required (if config says so, and replay overlay is not currently showing) - [self autoplayIfRequired]; - } - // Video is still pre-caching. Will show on top of ad image when pre-cached from carousel view - else - { - ALLog(@"Video still waiting to be pre-cached for slot (%@)...", ad.adIdNumber); - } - } - else - { - // No special treatment for non-middle cards - } - } - else - { - ALLog(@"Begin refresh for nil slot. Clearing view..."); - [self clearView]; - } -} - -#pragma mark - Video Action Methods - -- (void)autoplayIfRequired -{ - self.adImageView.userInteractionEnabled = NO; - - // Update the mute button regardless if we're autoplaying since we'll have to animate it regardless - [self updateMuteState]; - - // If the video is not waiting to be replayed - if ( !self.cardState.replayOverlayVisible ) - { - // If configuration says we should autoplay - if ( kIsAutoplay ) - { - [self playVideoIfInactive]; - } - else - { - // If we're not going to autoplay the video, animate in the video controls - [UIView animateWithDuration: 0.5f animations:^{ - self.playButton.alpha = 1.0f; - }]; - } - } -} - -- (void)playVideoIfInactive -{ - if ( [self isCurrentlyPlayingVideo] ) - { - ALLog(@"Attempting to play a video that's already playing"); - } - else - { - ALLog(@"Video play requested..."); - - self.videoView.playerLayer.backgroundColor = kVideoViewBackgroundWhilePlayingColor.CGColor; - self.videoView.backgroundColor = kVideoViewBackgroundWhilePlayingColor; - - // Prepare the view to play video - [UIView animateWithDuration: 1.0f animations:^{ - - self.muteButton.alpha = 1.0f; - self.playButton.alpha = 0.0f; - - // Crossfade the video in and the ad image out then autoplay the video if needed - self.adImageView.alpha = 0.0f; - self.videoView.alpha = 1.0f; - }]; - - self.adImageView.userInteractionEnabled = NO; - - // When replaying a video we do not fade out the replay overlay - self.replayOverlayView.alpha = 0.0f; - self.cardState.replayOverlayVisible = NO; - - // Attach new observer to get notified when video ends - [[NSNotificationCenter defaultCenter] addObserver: self - selector: @selector(playerItemDidReachEnd:) - name: AVPlayerItemDidPlayToEndTimeNotification - object: self.videoView.player.currentItem]; - - // Prepare the video - self.videoPlayer.mediaSource = self.ad.videoURL; - [self seekToPosition: self.cardState.lastMediaPlayerPosition]; - self.cardState.videoStarted = YES; - [self.videoPlayer playVideo]; - - - // Track the video start if we didn't track it yet - if ( !self.cardState.wasVideoStartTracked ) - { - ALLog(@"Tracking video start for native ad (%@)", self.ad.adIdNumber); - [self.sdk.postbackService dispatchPostbackAsync: self.ad.videoStartTrackingURL andNotify: nil]; - - self.cardState.videoStartTracked = YES; - } - } -} - -- (void)setInactive -{ - self.adImageView.alpha = 1.0f; - self.adImageView.userInteractionEnabled = YES; - self.videoView.alpha = 0.0f; - self.muteButton.alpha = 0.0f; - self.playButton.alpha = 0.0f; - - // Reset background colors - self.backgroundColor = kVideoViewBackgroundColor; - self.videoView.playerLayer.backgroundColor = kVideoViewBackgroundColor.CGColor; - self.videoView.backgroundColor = kVideoViewBackgroundColor; - - [self deactivateIfNeeded]; -} - -- (void)playerItemDidReachEnd:(NSNotification *)notification -{ - ALLog(@"Video finished playing for native ad (%@)", self.ad.adIdNumber); - - self.cardState.lastMediaPlayerPosition = 0.0f; - self.cardState.videoCompleted = YES; - self.cardState.replayOverlayVisible = YES; - - [UIView animateWithDuration: 0.5f animations:^{ - self.muteButton.alpha = 0.0f; - self.replayOverlayView.alpha = 1.0f; - }]; - - [self handleVideoStopPlaying]; -} - -#pragma mark - Action Methods - -- (void)didTapMuteButton:(UIButton *)muteButton -{ - self.cardState.muteState = self.cardState.muteState == ALMuteStateMuted ? ALMuteStateUnmuted : ALMuteStateMuted; - [self updateMuteState]; -} - -- (void)didTapPlayButton:(UIButton *)sender -{ - [self playVideoIfInactive]; -} - -- (void)didTapReplayButton:(UIButton *)sender -{ - [self playVideoIfInactive]; -} - -- (void)didTapLearnMoreButton:(UIButton *)sender -{ - ALLog(@"Redirecting from Learn More button"); - [self handleClick]; -} - -- (void)didTapVideo:(UITapGestureRecognizer *)tapGesture -{ - if ( kVideoClicksThrough ) - { - ALLog(@"Redirecting from video click"); - [self handleClick]; - [self setInactive]; - } - else - { - if ( [self isCurrentlyPlayingVideo] ) - { - [self setInactive]; - [UIView animateWithDuration: 0.5f animations:^{ - self.playButton.alpha = 1.0f; - }]; - } - else - { - [self playVideoIfInactive]; - } - } -} - -- (void)didTapAdImage:(UITapGestureRecognizer *)tapGesture -{ - ALLog(@"Redirecting from ad image click"); - [self handleClick]; -} - -- (void)handleClick -{ - if ( self.cardView ) - { - [self.cardView handleClickForAd: self.ad]; - } - else - { - [self.ad launchClickTarget]; - } -} - -#pragma mark - Video Utility Methods - -- (Float64)currentVideoPosition -{ - return CMTimeGetSeconds(self.videoView.player.currentTime); -} - -- (Float64)videoDuration -{ - return CMTimeGetSeconds(self.videoPlayer.playerAsset.duration); -} - -- (NSNumber *)percentViewed -{ - Float64 viewedRatio = [self currentVideoPosition] / [self videoDuration]; - return @( viewedRatio * 100 ); -} - -- (UIImage *)frameForVideoAtCurrentPosition -{ - AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset: self.videoPlayer.playerAsset]; - - // Set the tolerance so we have a precise screenshot - if ( [imageGenerator respondsToSelector: @selector(setRequestedTimeToleranceBefore:)] && - [imageGenerator respondsToSelector: @selector(setRequestedTimeToleranceAfter:)] ) - { - [imageGenerator setRequestedTimeToleranceBefore: kCMTimeZero]; - [imageGenerator setRequestedTimeToleranceAfter: kCMTimeZero]; - } - - return [UIImage imageWithCGImage: [imageGenerator copyCGImageAtTime: self.videoView.player.currentItem.currentTime - actualTime: nil - error: nil]]; -} - -- (void)handleVideoStopPlaying -{ - self.videoView.playerLayer.backgroundColor = kVideoViewBackgroundColor.CGColor; - - if ( kRenderVideoScreenshotAsFallbackImage ) - { - self.cardState.screenshot = [self frameForVideoAtCurrentPosition]; - self.adImageView.image = self.cardState.screenshot; - - // Save the video rect, so at layoutSubviews: in an inactive card, we know what aspect ratio size the screenshot - // should be rendered in. - self.cardState.videoRect = self.videoView.playerLayer.videoRect; - } - - [[NSNotificationCenter defaultCenter] removeObserver: self name: AVPlayerItemDidPlayToEndTimeNotification object: nil]; - - // Track video completion if we havn't already - if ( self.cardState.videoStarted ) - { - NSURL* postbackUrl = [self.ad videoEndTrackingURL: [[self percentViewed] unsignedIntegerValue] firstPlay: self.cardState.firstPlayback]; - [self.sdk.postbackService dispatchPostbackAsync: postbackUrl andNotify: nil]; - } - - self.cardState.firstPlayback = NO; -} - -- (BOOL)isCurrentlyPlayingVideo -{ - return self.videoView.player.rate > 0.0f; -} - -- (void)seekToPosition:(Float64)position -{ - CMTimeScale timeScale = self.videoView.player.currentItem.asset.duration.timescale; - CMTime time = CMTimeMakeWithSeconds(position, timeScale); - [self.videoView.player seekToTime: time toleranceBefore: kCMTimeZero toleranceAfter: kCMTimeZero]; -} - -- (void)updateMuteState -{ - ALMuteState currentState = self.cardState.muteState; - - // If the current state is unspecify, determine if it should be muted or unmuted according to settings - if ( currentState == ALMuteStateUnspecified ) - { - currentState = kConfigIsMuted ? ALMuteStateMuted : ALMuteStateUnmuted; - self.cardState.muteState = currentState; - } - - if ( currentState == ALMuteStateMuted ) - { - self.muteButton.selected = YES; - self.videoView.player.muted = YES; - } - else if ( currentState == ALMuteStateUnmuted ) - { - self.muteButton.selected = NO; - self.videoView.player.muted = NO; - } -} - -#pragma mark - Utility Methods - -- (void)clearView -{ - self.adImageView.image = nil; - self.adImageView.alpha = 0.0f; - self.adImageView.userInteractionEnabled = NO; - self.videoView.alpha = 0.0f; - self.replayOverlayView.alpha = 0.0f; - self.cardState = nil; -} - -// Called when resuming app or going back into the containing VC -- (void)reactivateIfNeeded -{ - if ( self.cardState.currentlyActive && [self.ad isVideoPrecached] ) - { - [self autoplayIfRequired]; - } -} - -// Called when pausing app or leaving VC *OR* when setting a card inactive -- (void)deactivateIfNeeded -{ - if ( [self isCurrentlyPlayingVideo] ) - { - self.cardState.lastMediaPlayerPosition = [self currentVideoPosition]; - - [self.videoPlayer stopVideo]; - [self handleVideoStopPlaying]; - } -} - -- (void)destroyVideoPlayer -{ - // We don't need a video player; remove any one left behind. - [self.videoPlayer stopVideo]; - self.videoPlayer = nil; - - [self.videoView removeFromSuperview]; - self.videoView = nil; - - [self.muteButton removeFromSuperview]; - [self.playButton removeFromSuperview]; - - self.playButton = nil; - self.muteButton = nil; -} - -- (void)createVideoPlayerIfNeeded -{ - [self destroyVideoPlayer]; - - // Create video player only for middle card - if ( self.cardState.currentlyActive && [self.ad isVideoPrecached] ) - { - self.videoPlayer = [[ALNativeAdVideoPlayer alloc] initWithMediaSource: nil]; - self.videoView.player.actionAtItemEnd = AVPlayerActionAtItemEndPause; - self.videoView.playerLayer.backgroundColor = [UIColor clearColor].CGColor; - - self.videoView = self.videoPlayer.videoView; - [self.videoView.playerLayer setNeedsDisplay]; - self.videoView.backgroundColor = kVideoViewBackgroundColor; - - self.muteButton = [[UIButton alloc] init]; - self.muteButton.alpha = 0.0f; - [self.muteButton addTarget: self action: @selector(didTapMuteButton:) forControlEvents: UIControlEventTouchUpInside]; - - self.playButton = [[UIButton alloc] init]; - self.playButton.alpha = 0.0f; - [self.playButton addTarget: self action: @selector(didTapPlayButton:) forControlEvents: UIControlEventTouchUpInside]; - - UITapGestureRecognizer *videoTapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(didTapVideo:)]; - [self.videoView addGestureRecognizer: videoTapGesture]; - - [self insertSubview: self.videoView belowSubview: self.adImageView]; - [self insertSubview: self.playButton aboveSubview: self.adImageView]; - [self insertSubview: self.muteButton aboveSubview: self.videoView]; - - // Popualte the assets - [self.playButton setImage: [UIImage imageNamed: @"applovin_card_play"] forState: UIControlStateNormal]; - [self.muteButton setImage: [UIImage imageNamed: @"applovin_card_unmuted"] forState: UIControlStateNormal]; - [self.muteButton setImage: [UIImage imageNamed: @"applovin_card_muted"] forState: UIControlStateSelected]; - } -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.h deleted file mode 100644 index 7c14e79d75..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// ALCarouselReplayOverlayView.h -// sdk -// -// Created by Thomas So on 4/22/15. -// -// - -@import UIKit; -#import "ALCarouselMediaView.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - * This view provides a few buttons to allow the user to replay or click through an ad. - */ -@interface ALCarouselReplayOverlayView : UIView - -@property (strong, nonatomic) UIView *overlay; -@property (strong, nonatomic) UIButton *replayButton; -@property (strong, nonatomic) UIButton *replayIconButton; -@property (strong, nonatomic) UIButton *learnMoreButton; -@property (strong, nonatomic) UIButton *learnMoreIconButton; - -- (instancetype)initWithParentView:(ALCarouselMediaView *)parentView; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.m deleted file mode 100644 index 02a4d8768b..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselReplayOverlayView.m +++ /dev/null @@ -1,99 +0,0 @@ -// -// ALCarouselReplayOverlayView.m -// sdk -// -// Created by Thomas So on 4/22/15. -// -// - -#import "ALCarouselReplayOverlayView.h" -#import "ALCarouselViewSettings.h" - -@interface ALCarouselReplayOverlayView() -@property (weak, nonatomic) ALCarouselMediaView *mediaView; -@end - -@implementation ALCarouselReplayOverlayView - -#pragma mark - Initialization - -- (instancetype)initWithParentView:(ALCarouselMediaView *)parentView -{ - self = [super init]; - if ( self ) - { - self.mediaView = parentView; - - self.backgroundColor = [UIColor clearColor]; - - self.overlay = [[UIView alloc] init]; - - self.overlay.backgroundColor = kReplayOverlayBackgroundColor; - self.overlay.alpha = kConfigReplayOverlayAlpha; - [self addSubview: self.overlay]; - - self.replayIconButton = [[UIButton alloc] init]; - [self addSubview: self.replayIconButton]; - - self.replayButton = [[UIButton alloc] init]; - [self addSubview: self.replayButton]; - - self.learnMoreIconButton = [[UIButton alloc] init]; - [self addSubview: self.learnMoreIconButton]; - - self.learnMoreButton = [[UIButton alloc] init]; - [self addSubview: self.learnMoreButton]; - - [self.replayIconButton setTintColor: kButtonHighlightTint]; - [self.replayButton setTitleColor: kReplayTextColor forState: UIControlStateNormal]; - [self.replayButton setTitleColor: kButtonHighlightTint forState: UIControlStateHighlighted]; - [self.learnMoreButton setTitleColor: kReplayTextColor forState: UIControlStateNormal]; - [self.learnMoreButton setTitleColor: kButtonHighlightTint forState: UIControlStateHighlighted]; - [self.learnMoreIconButton setTintColor: kButtonHighlightTint]; - - [self.replayIconButton setImage: [UIImage imageNamed: @"applovin_card_replay"] forState: UIControlStateNormal]; - [self.learnMoreIconButton setImage: [UIImage imageNamed: @"applovin_card_learn_more"] forState: UIControlStateNormal]; - - [self.replayButton setTitle: kTextReplayVideo forState: UIControlStateNormal]; - [self.learnMoreButton setTitle: kTextLearnMore forState: UIControlStateNormal]; - } - return self; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - self.overlay.frame = self.bounds; - - const CGFloat replayButtonWidth = [self.replayButton sizeThatFits: CGSizeMake(CGFLOAT_MAX, 0.0f)].width; - const CGFloat totalReplayWidth = kPlayReplayWidth + kPadding + replayButtonWidth; - - const CGFloat learnMoreButtonWidth = [self.learnMoreButton sizeThatFits: CGSizeMake(CGFLOAT_MAX, 0.0f)].width; - const CGFloat totalLearnMoreWidth = kPlayReplayWidth + kPadding + learnMoreButtonWidth; - - const CGFloat totalContentHeight = (2*kPlayReplayHeight) + kPadding; - - // We will center and align depending on which button has the longer total width - const CGFloat longerWidth = totalReplayWidth >= totalLearnMoreWidth ? totalReplayWidth : totalLearnMoreWidth; - - self.replayIconButton.frame = CGRectMake(CGRectGetMidX(self.frame) - longerWidth/2.0f, - CGRectGetMidY(self.frame) - totalContentHeight/2.0f, - kPlayReplayWidth, - kPlayReplayHeight); - self.replayButton.frame = CGRectMake(CGRectGetMaxX(self.replayIconButton.frame) + kPadding, - CGRectGetMinY(self.replayIconButton.frame), - replayButtonWidth, - kPlayReplayHeight); - - self.learnMoreIconButton.frame = CGRectMake(CGRectGetMidX(self.frame) - longerWidth/2.0f, - CGRectGetMaxY(self.replayIconButton.frame) + kPadding, - kPlayReplayWidth, - kPlayReplayHeight); - self.learnMoreButton.frame = CGRectMake(CGRectGetMaxX(self.learnMoreIconButton.frame) + kPadding, - CGRectGetMaxY(self.replayIconButton.frame) + kPadding, - learnMoreButtonWidth, - kPlayReplayHeight); -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.h deleted file mode 100644 index ba438deb10..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// ALCarouselView.h -// -// Created by Thomas So on 3/30/15. -// Copyright (c) 2015, AppLovin Corporation. All rights reserved. -// - -@import AppLovinSDK; - -NS_ASSUME_NONNULL_BEGIN - -/** - * This class is used to display native ads to the user. - */ -@interface ALCarouselView : UIView - -/** - * An object conforming to the ALNativeAdGroupLoadDelegate protocol, which, if set, will be notified of ad load events. - */ -@property (weak, nonatomic, nullable) id loadDelegate; - -/** - * The current native ad(s) being displayed. - */ -@property (strong, nonatomic, readonly) NSArray *nativeAds; - -- (instancetype)initWithFrame:(CGRect)frame; -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk; -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk nativeAds:(NSArray *)nativeAds; -- (instancetype)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.m deleted file mode 100644 index 4a77221daa..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALCarouselView.m +++ /dev/null @@ -1,643 +0,0 @@ -// -// ALCarouselView.m -// -// Created by Thomas So on 3/30/15. -// Copyright (c) 2015, AppLovin Corporation. All rights reserved. -// - -@import AppLovinSDK; -#import "ALCarouselView.h" -#import "ALCarouselView+Internal.h" -#import "UIView+ALActivityIndicator.h" -#import "ALCarouselCardView.h" -#import "ALCarouselCardState.h" -#import "ALCarouselViewModel.h" -#import "ALCarouselViewSettings.h" -#import "ALDebugLog.h" - -@class ALCarouselView; - -/** - * This class acts as an intermediary between pre-cache events of slots and which card to notify. - */ -@interface ALCarouselPrecacheRouter : NSObject - -@property (copy, nonatomic) NSString *tag; -@property (weak, nonatomic) ALCarouselView *carouselView; - -- (instancetype)initWithCarouselView:(ALCarouselView *)carouselView; - -@end - -@interface ALCarouselView() - -@property (strong, nonatomic) ALSdk *sdk; -@property (weak, nonatomic) ALPostbackService *postbackService; - -@property (weak, atomic) NSArray *previousNativeAdsRendered; -@property (strong, nonatomic) ALCarouselViewModel *carouselModel; -@property (assign, nonatomic) NSInteger currentAdIndex; - -@property (strong, nonatomic) ALCarouselPrecacheRouter *precacheRouter; - -// This array has 5 card objets that are used to render the ad -@property (strong, nonatomic) NSArray *cardViews; -@property (strong, nonatomic) UIView *contentView; -@property (strong, nonatomic) UIPanGestureRecognizer *panGesture; - -@end - -#pragma mark ALCarouselView - -@implementation ALCarouselView -static NSString * const TAG = @"ALCarouselView"; - -// Card constants -static NSInteger const kNumSideCards = 2; -static NSInteger const kNumCards = 5; -static NSInteger const kMidCardIndex = 2; - -#pragma mark - Initialization - -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder: aDecoder]; - if ( self ) - { - [self baseInitWithSdk: [ALSdk shared]]; - } - return self; -} - -- (instancetype)init -{ - self = [super init]; - if (self) - { - self.sdk = [ALSdk shared]; - } - return self; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - return [self initWithFrame: frame sdk: [ALSdk shared]]; -} - -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk -{ - return [self initWithFrame: frame sdk: sdk nativeAds: @[]]; -} - -- (instancetype)initWithFrame:(CGRect)frame sdk:(ALSdk *)sdk nativeAds:(NSArray *)nativeAds -{ - self = [super initWithFrame: frame]; - if ( self ) - { - [self baseInitWithSdk: sdk]; - self.nativeAds = nativeAds; - } - return self; -} - -- (void)baseInitWithSdk:(ALSdk *)sdk -{ - self.sdk = sdk; - self.postbackService = sdk.postbackService; - - self.currentAdIndex = 0; - - self.precacheRouter = [[ALCarouselPrecacheRouter alloc] initWithCarouselView: self]; - - // Setup View - self.userInteractionEnabled = YES; - self.clipsToBounds = YES; - self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - self.backgroundColor = kCarouselBackgroundColor; - - self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; - self.panGesture.delegate = self; - self.panGesture.delaysTouchesBegan = NO; - self.panGesture.delaysTouchesEnded = NO; - [self addGestureRecognizer: self.panGesture]; - - self.contentView = [[UIView alloc] init]; - self.contentView.backgroundColor = kCarouselBackgroundColor; - [self addSubview: self.contentView]; - - NSMutableArray* tempCards = [NSMutableArray arrayWithCapacity: kNumCards]; - for ( NSInteger i = 0; i < kNumCards; ++i ) - { - ALCarouselCardView *cardView = [[ALCarouselCardView alloc] initWithSdk: sdk]; - cardView.backgroundColor = [UIColor clearColor]; - cardView.hidden = YES; - - - [self.contentView addSubview: cardView]; - - [tempCards addObject: cardView]; - } - - self.cardViews = [NSArray arrayWithArray: tempCards]; -} - --(void) didMoveToSuperview -{ - [super didMoveToSuperview]; - - // If there are attached from initialization - if ( self.nativeAds.count > 0 ) - { - // All of the objects in the array are checked to be of proper type in setter. Render. - [self renderAdsIfNeeded]; - } - // If there isn't currently any native ad(s) attached, load one. - else - { - [self al_showActivityIndicator]; - - // AppLovin SDK has deprecated loading of multiple native ads - [self.sdk.nativeAdService loadNextAdAndNotify: self]; - //[self.sdk.nativeAdService loadNativeAdGroupOfCount: kNativeAdsToLoadCount andNotify: self]; - } -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - const CGFloat cardWidth = (CGRectGetWidth(self.bounds) * kCardWidthPercentage) - (2 * kCardMargin); - const CGFloat contentWidth = kNumCards * cardWidth; - - CGRect contentFrame = CGRectZero; - contentFrame.origin.x = CGRectGetMidX(self.bounds) - (contentWidth/2); - contentFrame.size.width = contentWidth; - contentFrame.size.height = CGRectGetHeight(self.bounds); - self.contentView.frame = contentFrame; - - CGFloat currentX = 0.0f; - for ( ALCarouselCardView *cardView in self.cardViews ) - { - cardView.frame = CGRectMake(currentX, 0.0f, cardWidth, CGRectGetHeight(self.bounds)); - currentX += cardWidth; - } - - // Activity Views from category - self.activityIndicatorOverlay.frame = self.bounds; - self.activityIndicator.center = self.activityIndicatorOverlay.center; -} - -#pragma mark - Native Ad Load Delegate - -- (void)nativeAdService:(ALNativeAdService *)service didLoadAds:(NSArray *)ads -{ - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - - self.nativeAds = ads; - [self renderAdsIfNeeded]; - - @try - { - if ( [(id)self.loadDelegate respondsToSelector: @selector(nativeAdService:didLoadAds:)] ) - { - [self.loadDelegate nativeAdService: service didLoadAds: ads]; - } - } - @catch (NSException *exception) - { - ALLog(@"Unable to notify native ad load delegate because of exception: %@", exception); - } - }]; -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToLoadAdsWithError:(NSInteger)code -{ - ALLog(@"Native ad service did fail to load native ad with error: %ld", code); - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - - @try - { - if ( [(id)self.loadDelegate respondsToSelector: @selector(nativeAdService:didFailToLoadAdsWithError:)] ) - { - [self.loadDelegate nativeAdService: service didFailToLoadAdsWithError: code]; - } - } - @catch (NSException *exception) - { - ALLog(@"Unable to notify native ad load delegate about failing to load because of exception: %@", exception); - } - }]; -} - -#pragma mark - View Rendering - -- (void)renderAdsIfNeeded -{ - if ( [self.nativeAds isEqual: self.previousNativeAdsRendered] ) - { - ALLog(@"Attempting to re-render native ad(s)"); - } - else - { - // Keep track of native ad(s) rendered to prevent re-rendering - self.previousNativeAdsRendered = self.nativeAds; - - self.carouselModel = [[ALCarouselViewModel alloc] initWithNativeAds: self.nativeAds]; - - self.panGesture.enabled = self.nativeAds.count > 1; // Don't allow swiping if only one card - - self.currentAdIndex = 0; - - [self refreshView]; - } -} - -- (void)refreshView -{ - ALLog(@"Begin refreshing carousel view for number of native ads: %lu", self.nativeAds.count); - - // Update/save states before refreshing each card - for ( ALCarouselCardView *cardView in self.cardViews ) - { - [cardView.mediaView setInactive]; - } - - for ( NSInteger cardIndex = 0; cardIndex < kNumCards ; ++cardIndex ) - { - ALLog(@"Begin refreshing for card at index %ld", cardIndex); - - ALCarouselCardView *cardView = self.cardViews[cardIndex]; - - // Determine what slot should be displaying in the card with index 'cardIndex' now - // Please Note: Will return an out-of-bounds if we're not supposed to render ad for card at this index - NSInteger adIndex = [self adIndexForCardIndex: cardIndex]; - - // If ad exists for this card view, render - if ( (adIndex >= 0) && (adIndex < self.nativeAds.count) ) - { - ALLog(@"Refreshing card view at index: %ld with slot at index: %ld", cardIndex, adIndex); - ALNativeAd *ad = self.nativeAds[adIndex]; - - ALCarouselCardState *cardState = [self.carouselModel cardStateAtNativeAdIndex: adIndex]; - cardState.currentlyActive = (cardIndex == kMidCardIndex); - - if ( [ad isImagePrecached] ) - { - ALLog(@"Card at index: %ld currently has its images pre-cached", cardIndex); - - [cardView renderViewForNativeAd: ad cardState: cardState]; - - // Only middle (active) card can be clicked on - cardView.userInteractionEnabled = cardState.currentlyActive; - cardView.hidden = NO; - - if ( cardState.currentlyActive ) - { - // Handle events when middle card is displayed - [cardView trackImpression]; - } - } - // If images are not pre-cached, then videos are not pre-cached as well - else - { - ALLog(@"Card at index: %ld is not pre-cached", cardIndex); - - [cardView clearView]; - [cardView al_showActivityIndicator]; - cardView.hidden = NO; - - if ( cardState.precaching ) - { - ALLog(@"Card at index: %ld is already currently pre-caching", cardIndex); - } - else - { - cardState.precaching = YES; - - ALLog(@"Begin pre-caching for card at index: %ld", cardIndex); - [self.sdk.nativeAdService precacheResourcesForNativeAd: ad andNotify: self.precacheRouter]; - } - } - } - // Slot does not exist for this card view, hide - else - { - ALLog(@"Hiding card at card index: %ld", cardIndex); - - [cardView clearView]; - cardView.hidden = YES; - - if ( cardIndex == kMidCardIndex ) - { - ALLog(@"Hiding middle card because of nil ad."); - } - } - } - - [self al_hideActivityIndicatorAnimated: YES]; - - ALLog(@"Finish refreshing carousel view"); -} - -- (void)clearView -{ - for ( ALCarouselCardView *cardView in self.cardViews ) - { - [cardView clearView]; - } - [self.carouselModel removeAllObjects]; -} - -#pragma mark - Overridden Getters/Setters - -- (void)setNativeAds:(NSArray * __nullable)nativeAds -{ - if ( self.nativeAds.count > 0 ) - { - // Check if array contains objects of the proper ad type - for ( id obj in self.nativeAds ) - { - if ( ![obj isKindOfClass: [ALNativeAd class]] ) - { - // Found an object of invalid type - ALLog(@"Found an object of invalid type (%@) in nativeAds", NSStringFromClass([obj class])); - - return; - } - } - } - else - { - // We clear the view if native ads is set to an empty array - ALLog(@"Setting native ads of count 0. Clearing view..."); - [self clearView]; - } - - _nativeAds = nativeAds; -} - -- (void)setCurrentAdIndex:(NSInteger)currentAdIndex -{ - if ( currentAdIndex < self.nativeAds.count ) - { - if ( self.currentAdIndex == currentAdIndex ) - { - ALLog(@"Setting same current ad index of %ld", currentAdIndex); - } - else - { - ALLog(@"Setting new current ad index of %ld", currentAdIndex); - - _currentAdIndex = currentAdIndex; - - [self refreshView]; - } - } - else - { - ALLog(@"Setting out-of-bounds index of %ld", currentAdIndex); - } -} - -#pragma mark - Utility - -- (NSInteger)adIndexForCardIndex:(NSUInteger)cardIndex -{ - return self.currentAdIndex + cardIndex - kNumSideCards; -} - -#pragma mark - Gesture Recognizers - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - if ( [gestureRecognizer isEqual: self.panGesture] ) - { - // Our pan gesture should only recognize horizontal pans - CGPoint translation = [self.panGesture velocityInView: self]; - return fabs(translation.y) < fabs(translation.x); - } - - return YES; -} - -- (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer -{ - switch ( recognizer.state ) - { - case UIGestureRecognizerStateChanged: - { - CGFloat xOffset = [recognizer translationInView: self].x; - self.contentView.frame = CGRectOffset(self.contentView.frame, xOffset, 0.0f); - - [recognizer setTranslation: CGPointZero inView: self]; - - break; - } - case UIGestureRecognizerStateEnded: - { - const CGFloat cardWidth = (CGRectGetWidth(self.bounds) * kCardWidthPercentage) - (2 * kCardMargin); - const CGFloat contentOffset = fabs(self.center.x - self.contentView.center.x); - const CGFloat percentageSwiped = 1.0f - (contentOffset/CGRectGetWidth(self.bounds)); - const CGFloat springDuration = percentageSwiped * kSpringDuration; - - const BOOL exceedsThreshold = contentOffset > kConfigSwipeThreshold; - const BOOL leftToRight = [recognizer velocityInView: self].x > 0.0f; - - // If user is swiping left to right - if ( leftToRight ) - { - // If the middle card has a slot to the left of it, then execute the swipe - if ( self.currentAdIndex >= 1 && exceedsThreshold ) - { - [UIView animateWithDuration: springDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningGoNextCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake( (CGRectGetWidth(self.frame)/2.0f) + cardWidth, self.contentView.center.y); - } - completion: ^(BOOL finished) { - - if ( finished ) - { - --self.currentAdIndex; - [self setNeedsLayout]; - } - }]; - } - // There are no slots to the left of the middle card anymore, spring back - else - { - [UIView animateWithDuration: kSpringDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningReturnSameCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake(0.5f * CGRectGetWidth( self.frame ), self.contentView.center.y); - } - completion:nil]; - } - } - // We are swiping right to left - else - { - // If there is a slot to the right of the middle card, execute the swipe - if ( self.currentAdIndex < [self.carouselModel nativeAdsCount]-1 && exceedsThreshold ) - { - [UIView animateWithDuration: springDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningGoNextCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake( (CGRectGetWidth(self.frame)/2.0f) - cardWidth, self.contentView.center.y); - } - completion:^(BOOL finished) { - - if ( finished ) - { - ++self.currentAdIndex; - [self setNeedsLayout]; - } - }]; - } - // There are no slots to the right of the middle card anymore. Spring back - else - { - [UIView animateWithDuration: kSpringDuration - delay: kDelay - usingSpringWithDamping: kSpringDampeningReturnSameCard - initialSpringVelocity: kInitialSpringVelocity - options: UIViewAnimationOptionCurveEaseInOut - animations: ^{ - - self.contentView.center = CGPointMake(0.5f * CGRectGetWidth( self.frame ), self.contentView.center.y); - } - completion:nil]; - } - } - break; - } - default: - { - break; - } - } -} - -@end - -#pragma mark ALCarouselPrecacheRouter - -@implementation ALCarouselPrecacheRouter - -#pragma mark - Initialization - -- (instancetype)initWithCarouselView:(ALCarouselView *)carouselView -{ - self = [super init]; - - if ( self ) - { - self.tag = @"ALCarouselPrecacheRouter"; - self.carouselView = carouselView; - } - - return self; -} - -#pragma mark - Precache Delegate Methods - -- (void)nativeAdService:(ALNativeAdService *)service didPrecacheImagesForAd:(ALNativeAd *)ad -{ - ALLog(@"Finished pre-caching images for slot (%@). Rendering...", ad.adIdNumber); - - const NSUInteger index = [self.carouselView.nativeAds indexOfObject: ad]; - - if ( index != NSNotFound ) - { - const NSInteger cardIndex = [self cardIndexForAdIndex: index]; - ALCarouselCardView* cardView = self.carouselView.cardViews[cardIndex]; - ALCarouselViewModel* model = self.carouselView.carouselModel; - ALCarouselCardState* cardState = [model cardStateAtNativeAdIndex: index]; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [cardView renderViewForNativeAd: ad cardState: cardState]; - - if (cardIndex == kMidCardIndex) { - [cardView trackImpression]; - } - - cardView.hidden = NO; - }]; - } - else - { - ALLog(@"Finished pre-caching images for ad (%@). Card is not on screen, stashing...", ad.adIdNumber); - } -} - -- (void)nativeAdService:(ALNativeAdService *)service didPrecacheVideoForAd:(ALNativeAd *)ad -{ - if ( ad.videoURL ) - { - const NSUInteger index = [self.carouselView.nativeAds indexOfObject: ad]; - ALCarouselCardState *cardState = [self.carouselView.carouselModel cardStateAtNativeAdIndex: index]; - - // If video is loaded for a currently active ad, render the slot - if ( index != NSNotFound && cardState.currentlyActive ) - { - ALLog(@"Finished pre-caching for slot (%@) with valid video in active card", ad.adIdNumber); - - const NSInteger cardIndex = [self cardIndexForAdIndex: index]; - ALCarouselCardView *cardView = self.carouselView.cardViews[cardIndex]; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - - [cardView.mediaView renderViewForNativeAd: ad cardState: cardState]; - }]; - } - else - { - ALLog(@"Finished pre-caching video for ad (%@). Card is not on screen, stashing...", ad.adIdNumber); - } - } - else - { - // Finished pre-caching for slot without video - ALLog(@"Finished pre-caching for ad (%@) without video", ad.adIdNumber); - } - - [self.carouselView.carouselModel cardStateForNativeAd: ad].precaching = NO; -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToPrecacheImagesForAd:(ALNativeAd *)ad withError:(NSInteger)errorCode -{ - // Have activity indicator remain on card - [self.carouselView.carouselModel cardStateForNativeAd: ad].precaching = YES; - - ALLog(@"Failed to precache images for ad (%@) with error code: %ld", ad.adIdNumber, errorCode); -} - -- (void)nativeAdService:(ALNativeAdService *)service didFailToPrecacheVideoForAd:(ALNativeAd *)ad withError:(NSInteger)errorCode -{ - // If the slot already has its images pre-cached, it means video failed to pre-cache. Just ignore that - [self.carouselView.carouselModel cardStateForNativeAd: ad].precaching = NO; - - ALLog(@"Failed to precache video for ad (%@) with error code: %ld", ad.adIdNumber, errorCode); -} - -#pragma mark - Utility - -- (NSUInteger)cardIndexForAdIndex:(NSUInteger)slotIndex -{ - return kMidCardIndex + slotIndex - self.carouselView.currentAdIndex; -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.h deleted file mode 100644 index fd5806828b..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// ALVideoView.h -// sdk -// -// Created by Matt Szaro on 6/23/14. -// -// - -@import AppLovinSDK; -@import AVFoundation; - -NS_ASSUME_NONNULL_BEGIN - -@interface ALNativeAdVideoView : UIView - -@property (strong, nonatomic, readonly) AVPlayer *player; -@property (strong, nonatomic, readonly) AVPlayerLayer* playerLayer; - -- (instancetype)initWithPlayer:(AVPlayer *)aPlayer; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.m deleted file mode 100644 index 279a6321fe..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /Carousel UI/Views/ALNativeAdVideoView.m +++ /dev/null @@ -1,48 +0,0 @@ -// -// ALVideoView.m -// sdk -// -// Created by Matt Szaro on 6/23/14. -// -// - -#import "ALNativeAdVideoView.h" - -@interface ALNativeAdVideoView() -@property (strong, nonatomic, readwrite) AVPlayer *player; -@end - -@implementation ALNativeAdVideoView -@dynamic player, playerLayer; - --(instancetype) initWithPlayer:(AVPlayer *)aPlayer -{ - self = [super init]; - if(self) - { - self.player = aPlayer; - } - return self; -} - -+(Class) layerClass -{ - return [AVPlayerLayer class]; -} - --(AVPlayerLayer*) playerLayer -{ - return (AVPlayerLayer*) self.layer; -} - --(AVPlayer*) player -{ - return self.playerLayer.player; -} - --(void) setPlayer: (AVPlayer *) aPlayer -{ - self.playerLayer.player = aPlayer; -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.h deleted file mode 100644 index 2b720eab1e..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// ALDemoArticle.h -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface ALDemoArticle : NSObject - -@property (nonatomic, copy) NSString *title; -@property (nonatomic, copy) NSString *pubDate; -@property (nonatomic, copy) NSString *creator; -@property (nonatomic, copy) NSString *articleDescription; -@property (nonatomic, strong) NSURL *link; - -@property (nonatomic, assign) BOOL isAd; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.m deleted file mode 100644 index 2b24785788..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoArticle.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// ALDemoArticle.m -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALDemoArticle.h" - -@implementation ALDemoArticle - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.h deleted file mode 100644 index 0b76784375..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// ALDemoRSSFeedRetriever.h -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import -#import "ALDemoArticle.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ALDemoRSSFeedRetriever : NSObject - -typedef void(^ALDemoRSSFeedRetrieverBlock)(NSError *__nullable error, NSArray *articles); - -+ (ALDemoRSSFeedRetriever *)sharedRetriever; -- (void)startParsingWithCompletion:(ALDemoRSSFeedRetrieverBlock)completion; - -@end - -NS_ASSUME_NONNULL_END diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.m b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.m deleted file mode 100644 index 5d039dfefb..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Feed /RSS Feed Parsing/ALDemoRSSFeedRetriever.m +++ /dev/null @@ -1,121 +0,0 @@ -// -// ALDemoRSSFeedRetriever.m -// iOS-SDK-Demo -// -// Created by Thomas So on 11/12/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -#import "ALDemoRSSFeedRetriever.h" - -@interface ALDemoRSSFeedRetriever() -@property (nonatomic, copy, nullable) NSString *currentElementName; -@property (nonatomic, strong, nullable) ALDemoArticle *currentArticle; - -@property (nonatomic, strong) NSMutableArray *articles; -@property (nonatomic, copy) ALDemoRSSFeedRetrieverBlock completionBlock; -@end - -@implementation ALDemoRSSFeedRetriever -static NSString *const kRSSFeedURL = @"https://blog.applovin.com/feed/"; - -+ (ALDemoRSSFeedRetriever *)sharedRetriever -{ - static dispatch_once_t pred; - static ALDemoRSSFeedRetriever *manager = nil; - dispatch_once(&pred, ^{ - manager = [[self alloc] init]; - }); - return manager; -} - -- (instancetype)init -{ - self = [super init]; - if ( self ) - { - self.articles = [NSMutableArray array]; - } - return self; -} - -- (void)startParsingWithCompletion:(ALDemoRSSFeedRetrieverBlock)completion -{ - // Do not retrieve if we already have retrieved some artivcles, just call completion - if ( self.articles.count > 0 ) - { - completion( nil, [NSArray arrayWithArray: self.articles] ); - } - else - { - self.completionBlock = completion; - - NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL: [NSURL URLWithString: kRSSFeedURL]]; - [parser setDelegate: self]; - [parser parse]; - } -} - -#pragma mark - Parser Delegate - -- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict -{ - self.currentElementName = elementName; - if ( [elementName isEqualToString: @"item"] ) - { - // Start of the parsing of a new article - - if ( self.articles.count == 3 ) - { - // Lets place an ad in the 4th slot - ALDemoArticle *adFauxArticle = [[ALDemoArticle alloc] init]; - adFauxArticle.isAd = YES; - [self.articles addObject: adFauxArticle]; - } - - self.currentArticle = [[ALDemoArticle alloc] init]; - [self.articles addObject: self.currentArticle]; - } -} - -- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string -{ - if ( self.currentArticle ) - { - if ( [self.currentElementName isEqualToString: @"title"] ) - { - self.currentArticle.title = string; - } - else if ( [self.currentElementName isEqualToString: @"link"] ) - { - self.currentArticle.link = [NSURL URLWithString: string]; - } - else if ( [self.currentElementName isEqualToString: @"pubDate"] ) - { - self.currentArticle.pubDate = [string substringToIndex: 11]; - } - else if ( [self.currentElementName isEqualToString: @"dc:creator"] ) - { - self.currentArticle.creator = string; - } - else if ( [self.currentElementName isEqualToString: @"description"] ) - { - self.currentArticle.articleDescription = [string stringByReplacingOccurrencesOfString: @"[…]" withString: @"..."]; - } - - // Reset current element name after we finish setting it - self.currentElementName = @""; - } -} - -- (void)parserDidEndDocument:(NSXMLParser *)parser -{ - self.completionBlock( nil, [NSArray arrayWithArray: self.articles] ); -} - -- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError -{ - self.completionBlock( parseError, @[] ); -} - -@end diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Programattic/ALDemoNativeAdProgrammaticViewController.swift b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Programattic/ALDemoNativeAdProgrammaticViewController.swift deleted file mode 100644 index fb37384cee..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/AppLovin/Native/Programattic/ALDemoNativeAdProgrammaticViewController.swift +++ /dev/null @@ -1,193 +0,0 @@ -// -// ALDemoNativeAdProgrammaticViewController.swift -// iOS-SDK-Demo -// -// Created by Thomas So on 9/25/15. -// Copyright © 2015 AppLovin. All rights reserved. -// - -import UIKit - -// Additional documentation - https://applovin.com/integration#iosNative - -class ALDemoNativeAdProgrammaticViewController : ALBaseAdViewController -{ - @IBOutlet weak var precacheButton: UIBarButtonItem! - @IBOutlet weak var showButton: UIBarButtonItem! - - @IBOutlet weak var impressionStatusLabel: UILabel! - - @IBOutlet weak var appIcon: UIImageView! - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var rating: UIImageView! - @IBOutlet weak var descriptionLabel: UILabel! - @IBOutlet weak var mediaView: ALCarouselMediaView! - @IBOutlet weak var ctaButton: UIButton! - - var nativeAd: ALNativeAd? - - override func viewDidLoad() - { - super.viewDidLoad() - - appIcon.layer.masksToBounds = true - appIcon.layer.cornerRadius = 3 - - ctaButton.layer.masksToBounds = true - ctaButton.layer.cornerRadius = 3 - - setUIElementsHidden(true) - } - - // MARK: Action Methods - - @IBAction func loadNativeAd(_ sender: AnyObject!) - { - logCallback() - - precacheButton.isEnabled = false - showButton.isEnabled = false - - impressionStatusLabel.text = "No impression to track" - - ALSdk.shared()!.nativeAdService.loadNextAdAndNotify(self) - } - - @IBAction func precacheNativeAd(_ sender: AnyObject!) - { - // You can use our pre-caching to retrieve assets (app icon, ad image, ad video) locally. OR you can do it with your preferred caching framework. - // iconURL, imageURL, videoURL needs to be retrieved manually before you can render them - - logCallback() - - if let ad = nativeAd - { - ALSdk.shared()!.nativeAdService.precacheResources(for: ad, andNotify: self) - } - } - - @IBAction func showNativeAd(_ sender: AnyObject!) - { - logCallback() - - if let ad = nativeAd, let iconURL = ad.iconURL - { - if let imageData = try? Data(contentsOf: iconURL) - { - appIcon.image = UIImage(data: imageData ) // Local URL - } - - titleLabel.text = ad.title - descriptionLabel.text = ad.descriptionText - ctaButton.setTitle(ad.ctaText, for: .normal) - - let starFilename = "Star_Sprite_\(String(describing: ad.starRating?.stringValue))" - rating.image = UIImage(named: starFilename) - - // NOTE - Videos have aspect ratio of 1:1.85 - mediaView.renderView(for: ad) - - setUIElementsHidden(false) - - // - // You are responsible for firing all necessary postback URLs - // - trackImpression(ad) - - view.layoutIfNeeded() - } - } - - @IBAction func ctaPressed(_ sender: AnyObject!) - { - nativeAd?.launchClickTarget() - } - - func trackImpression(_ ad: ALNativeAd!) - { - // Callbacks may not happen on main queue - DispatchQueue.main.async { - ad.trackImpressionAndNotify(self) - } - } - - func setUIElementsHidden(_ hidden: Bool) - { - appIcon.isHidden = hidden - titleLabel.isHidden = hidden - rating.isHidden = hidden - descriptionLabel.isHidden = hidden - mediaView.isHidden = hidden - ctaButton.isHidden = hidden - } -} - -extension ALDemoNativeAdProgrammaticViewController : ALPostbackDelegate -{ - func postbackService(_ postbackService: ALPostbackService, didExecutePostback postbackURL: URL) - { - // Callbacks may not happen on main queue - DispatchQueue.main.async { - // Impression tracked! - self.impressionStatusLabel.text = "Impression tracked" - } - } - - func postbackService(_ postbackService: ALPostbackService, didFailToExecutePostback postbackURL: URL?, errorCode: Int) - { - // Callbacks may not happen on main queue - DispatchQueue.main.async { - // Impression could not be tracked. Retry the postback later. - self.impressionStatusLabel.text = "Impression failed to track with error code \(errorCode)" - } - } -} - -extension ALDemoNativeAdProgrammaticViewController : ALNativeAdLoadDelegate -{ - func nativeAdService(_ service: ALNativeAdService, didLoadAds ads: [Any]) - { - logCallback() - - // Callbacks may not happen on main queue - DispatchQueue.main.async { - self.nativeAd = ads.first as? ALNativeAd - self.precacheButton.isEnabled = true - } - } - - func nativeAdService(_ service: ALNativeAdService, didFailToLoadAdsWithError code: Int) - { - logCallback() - } -} - -extension ALDemoNativeAdProgrammaticViewController : ALNativeAdPrecacheDelegate -{ - func nativeAdService(_ service: ALNativeAdService, didPrecacheImagesFor ad: ALNativeAd) - { - logCallback() - } - - func nativeAdService(_ service: ALNativeAdService, didPrecacheVideoFor ad: ALNativeAd) - { - // This delegate method will get called whether an ad actually has a video to precache or not - logCallback() - - // Callbacks may not happen on main queue - DispatchQueue.main.async { - self.showButton.isEnabled = true - self.precacheButton.isEnabled = false - } - } - - func nativeAdService(_ service: ALNativeAdService, didFailToPrecacheImagesFor ad: ALNativeAd, withError errorCode: Int) - { - logCallback() - } - - func nativeAdService(_ service: ALNativeAdService, didFailToPrecacheVideoFor ad: ALNativeAd, withError errorCode: Int) - { - logCallback() - } -} diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/Base.lproj/Main.storyboard b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/Base.lproj/Main.storyboard index 9304a36621..b0f020975a 100644 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/Base.lproj/Main.storyboard +++ b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -100,48 +100,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -165,7 +125,7 @@ - + @@ -185,7 +145,7 @@ - + @@ -205,7 +165,7 @@ - + @@ -225,7 +185,7 @@ - + @@ -245,7 +205,7 @@ - + @@ -266,7 +226,7 @@ - + @@ -881,7 +841,7 @@ - + @@ -951,11 +911,11 @@ - + - + @@ -1150,7 +1110,7 @@ - + diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/MRECs.storyboard b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/MRECs.storyboard deleted file mode 100644 index 8369169094..0000000000 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App - Swift/Supporting Files/MRECs.storyboard +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App-Bridging-Header.h b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App-Bridging-Header.h index e6b1aecb10..f43d59c100 100644 --- a/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App-Bridging-Header.h +++ b/AppLovin MAX Demo App - Swift/AppLovin MAX Demo App-Bridging-Header.h @@ -5,7 +5,3 @@ // Created by Varsha Hanji on 4/1/20. // Copyright © 2020 AppLovin. All rights reserved. // - -#import "ALCarouselMediaView.h" -#import "ALDemoRSSFeedRetriever.h" -#import "ALDemoArticle.h" diff --git a/README.md b/README.md index 7f9d5af1db..4450f7e4b0 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,5 @@ To get started with the demo apps, follow the instructions below: ## Support We recommend using GitHub to file issues. For feature requests, improvements, questions or any other integration issues using MAX Mediation by AppLovin, contact us via our support page https://monetization-support.applovin.com/hc/en-us. +MRECs and native ads have been deprecated and will be removed in a future SDK release. +