Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
1
1weather
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
1weather
Commits
4d5d2068
Commit
4d5d2068
authored
Apr 29, 2021
by
Demid Merzlyakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
InApp: hide ads when the app is purchased.
parent
8c8185a9
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
194 additions
and
4 deletions
+194
-4
1Weather.xcodeproj/project.pbxproj
+12
-0
1Weather/Common/Constants.swift
+2
-0
1Weather/InApps/OLInAppStoreManager.swift
+159
-0
1Weather/Resources/en.lproj/Localizable.strings
+9
-0
1Weather/StuffThatIsPresentInTheMainProject.swift
+2
-2
1Weather/UI/View controllers/NWSAlert/Cells/NWSAlertCellFactory.swift
+9
-1
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
+1
-1
No files found.
1Weather.xcodeproj/project.pbxproj
View file @
4d5d2068
...
@@ -252,6 +252,7 @@
...
@@ -252,6 +252,7 @@
CEC5275D25E8E50B00DA58A5
/* WdtDailySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
;
};
CEC5275D25E8E50B00DA58A5
/* WdtDailySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
;
};
CEC5276025E92DDA00DA58A5
/* WdtHourlySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
;
};
CEC5276025E92DDA00DA58A5
/* WdtHourlySummary.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
;
};
CEC7D8C42639FAF600B8836D
/* Global.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC7D8C32639FAF500B8836D
/* Global.swift */
;
};
CEC7D8C42639FAF600B8836D
/* Global.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC7D8C32639FAF500B8836D
/* Global.swift */
;
};
CEC7D8EE2639FE2700B8836D
/* OLInAppStoreManager.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC7D8ED2639FE2700B8836D
/* OLInAppStoreManager.swift */
;
};
CEC8FBAF2639756A0001A6BF
/* OnboardingViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
;
};
CEC8FBAF2639756A0001A6BF
/* OnboardingViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
;
};
CEC8FBB2263976240001A6BF
/* OnboardingCoordinator.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
;
};
CEC8FBB2263976240001A6BF
/* OnboardingCoordinator.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
;
};
CEC8FBB5263976400001A6BF
/* OnboardingViewModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
;
};
CEC8FBB5263976400001A6BF
/* OnboardingViewModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
;
};
...
@@ -575,6 +576,7 @@
...
@@ -575,6 +576,7 @@
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtDailySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC5275C25E8E50B00DA58A5
/* WdtDailySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtDailySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtHourlySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC5275F25E92DDA00DA58A5
/* WdtHourlySummary.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
WdtHourlySummary.swift
;
sourceTree
=
"<group>"
;
};
CEC7D8C32639FAF500B8836D
/* Global.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Global.swift
;
sourceTree
=
"<group>"
;
};
CEC7D8C32639FAF500B8836D
/* Global.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
Global.swift
;
sourceTree
=
"<group>"
;
};
CEC7D8ED2639FE2700B8836D
/* OLInAppStoreManager.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OLInAppStoreManager.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingViewController.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBAE2639756A0001A6BF
/* OnboardingViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingViewController.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingCoordinator.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBB1263976240001A6BF
/* OnboardingCoordinator.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingCoordinator.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingViewModel.swift
;
sourceTree
=
"<group>"
;
};
CEC8FBB4263976400001A6BF
/* OnboardingViewModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
OnboardingViewModel.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -694,6 +696,7 @@
...
@@ -694,6 +696,7 @@
CD1237C1255D5C5900C98139
/* 1Weather */
=
{
CD1237C1255D5C5900C98139
/* 1Weather */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
CEC7D8EC2639FE1B00B8836D
/* InApps */
,
CE14445D2638B6A8008E2162
/* 1Weather.entitlements */
,
CE14445D2638B6A8008E2162
/* 1Weather.entitlements */
,
CE13B78926247474007CBD4D
/* External */
,
CE13B78926247474007CBD4D
/* External */
,
CE13B7EC262480B3007CBD4D
/* Ads */
,
CE13B7EC262480B3007CBD4D
/* Ads */
,
...
@@ -1505,6 +1508,14 @@
...
@@ -1505,6 +1508,14 @@
path
=
ModelObjects
;
path
=
ModelObjects
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
};
};
CEC7D8EC2639FE1B00B8836D
/* InApps */
=
{
isa
=
PBXGroup
;
children
=
(
CEC7D8ED2639FE2700B8836D
/* OLInAppStoreManager.swift */
,
);
path
=
InApps
;
sourceTree
=
"<group>"
;
};
CEC8FBAD263975170001A6BF
/* Onboarding */
=
{
CEC8FBAD263975170001A6BF
/* Onboarding */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
...
@@ -2097,6 +2108,7 @@
...
@@ -2097,6 +2108,7 @@
CD86245E25E646350097F3FB
/* SunUvView.swift in Sources */
,
CD86245E25E646350097F3FB
/* SunUvView.swift in Sources */
,
CDF8F12D26208E7B00DB384A
/* MapCurrentTimeView.swift in Sources */
,
CDF8F12D26208E7B00DB384A
/* MapCurrentTimeView.swift in Sources */
,
CEAFF08325DFC67F00DF4EBF
/* Location.swift in Sources */
,
CEAFF08325DFC67F00DF4EBF
/* Location.swift in Sources */
,
CEC7D8EE2639FE2700B8836D
/* OLInAppStoreManager.swift in Sources */
,
CDECDB052629A6600087F9F2
/* RadarLayer.swift in Sources */
,
CDECDB052629A6600087F9F2
/* RadarLayer.swift in Sources */
,
CEFB857226174F7A00C5CDD2
/* Storage.swift in Sources */
,
CEFB857226174F7A00C5CDD2
/* Storage.swift in Sources */
,
CD82300725D6A73F00A05501
/* TodayConditionButton.swift in Sources */
,
CD82300725D6A73F00A05501
/* TodayConditionButton.swift in Sources */
,
...
...
1Weather/Common/Constants.swift
View file @
4d5d2068
...
@@ -13,3 +13,5 @@ let kEventInAppPurchasedCompleted = "EventInAppPurchasedCompleted"
...
@@ -13,3 +13,5 @@ let kEventInAppPurchasedCompleted = "EventInAppPurchasedCompleted"
let
a9AppKey
=
"2e440b094f7c44b4bae7044b764c61ac"
let
a9AppKey
=
"2e440b094f7c44b4bae7044b764c61ac"
let
kAdMoPubInitializationAdUnitId
=
"05bff78d4a4245bd98ff6b595c134889"
let
kAdMoPubInitializationAdUnitId
=
"05bff78d4a4245bd98ff6b595c134889"
let
kOLAppMetricsKey
:
String
=
"OLAppMetricsKey"
let
kOLAppMetricsKey
:
String
=
"OLAppMetricsKey"
//MARK: - InApp
let
kInAppOneWeatherProId
=
"com.onelouder.oneweather.inapp1"
1Weather/InApps/OLInAppStoreManager.swift
0 → 100644
View file @
4d5d2068
//
// OLInAppStoreManager.swift
// OneWeather
//
// Created by Steven G Pint on 5/16/17.
// Copyright © 2017 OneLouder, Inc. All rights reserved.
//
import
UIKit
import
StoreKit
// Ported from ObjC
protocol
OLInAppStoreManagerUIDelegate
:
class
{
func
viewControllerForPresentation
()
->
UIViewController
}
protocol
OLInAppStoreManagerDelegate
:
NSObjectProtocol
{
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
purchaseCompletedForProductId
productId
:
String
)
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
purchaseWillBeAdded
payment
:
SKPayment
)
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
purchaseFailedFor
transaction
:
SKPaymentTransaction
)
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
restoredCompletedForProductId
productId
:
String
)
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
restoreFailedWithError
error
:
Error
)
func
inAppStoreManager
(
_
inAppStoreManager
:
OLInAppStoreManager
,
restoreFailedWithMessage
message
:
String
)
}
class
OLInAppStoreManager
:
NSObject
{
private
let
log
=
Logger
(
componentName
:
"OLInAppStoreManager"
)
var
productIds
=
[
String
]()
weak
var
delegate
:
OLInAppStoreManagerDelegate
?
weak
var
uiDelegate
:
OLInAppStoreManagerUIDelegate
?
// SHARED INSTANCE
static
let
shared
=
OLInAppStoreManager
()
private
override
init
()
{
super
.
init
()
}
// MARK: - public methods
func
attemptPurchase
(
forProductId
productId
:
String
)
{
if
SKPaymentQueue
.
canMakePayments
()
{
productIds
.
append
(
productId
)
let
request
=
SKProductsRequest
(
productIdentifiers
:
Set
<
String
>
([
productId
]))
request
.
delegate
=
self
request
.
start
()
}
else
{
showAlert
(
"inapp.alert.prohibited.title"
.
localized
(),
message
:
"inapp.error.parental.control.cant.make.purchase"
.
localized
())
}
}
func
attemptRestore
(
forProductId
productId
:
String
)
{
if
SKPaymentQueue
.
canMakePayments
()
{
SKPaymentQueue
.
default
()
.
add
(
self
)
SKPaymentQueue
.
default
()
.
restoreCompletedTransactions
()
}
else
{
showAlert
(
"inapp.alert.prohibited.title"
.
localized
(),
message
:
"inapp.error.parental.control.cant.store"
.
localized
())
}
}
public
func
showAlert
(
_
title
:
String
?,
message
:
String
?)
->
Void
{
let
alert
=
UIAlertController
(
title
:
title
,
message
:
message
,
preferredStyle
:
.
alert
)
alert
.
addAction
(
UIAlertAction
(
title
:
"inapp.alert.ok"
.
localized
(),
style
:
.
default
,
handler
:
nil
))
self
.
uiDelegate
?
.
viewControllerForPresentation
()
.
present
(
alert
,
animated
:
true
,
completion
:
nil
)
}
}
// MARK: - SKProductsRequestDelegate
extension
OLInAppStoreManager
:
SKProductsRequestDelegate
{
func
productsRequest
(
_
request
:
SKProductsRequest
,
didReceive
response
:
SKProductsResponse
)
{
var
validProduct
:
SKProduct
?
=
nil
for
product
:
SKProduct
in
response
.
products
{
if
productIds
.
contains
(
product
.
productIdentifier
)
{
validProduct
=
product
break
}
}
if
let
validProduct
=
validProduct
{
let
payment
=
SKPayment
(
product
:
validProduct
)
delegate
?
.
inAppStoreManager
(
self
,
purchaseWillBeAdded
:
payment
)
SKPaymentQueue
.
default
()
.
add
(
self
)
SKPaymentQueue
.
default
()
.
add
(
payment
)
//[self updateToProLabel:NSLocalizedString(@"Confirming purchase...", nil) isUpdating:YES];
}
else
{
showAlert
(
"inapp.alert.product.not.available.title"
.
localized
(),
message
:
"inapp.alert.product.not.available.text"
.
localized
())
}
}
}
// MARK: - SKPaymentTransactionObserver - required
extension
OLInAppStoreManager
:
SKPaymentTransactionObserver
{
func
paymentQueue
(
_
queue
:
SKPaymentQueue
,
updatedTransactions
transactions
:
[
SKPaymentTransaction
])
{
for
transaction
:
SKPaymentTransaction
in
transactions
{
switch
transaction
.
transactionState
{
case
.
purchased
:
delegate
?
.
inAppStoreManager
(
self
,
purchaseCompletedForProductId
:
transaction
.
payment
.
productIdentifier
)
SKPaymentQueue
.
default
()
.
finishTransaction
(
transaction
)
case
.
failed
:
if
let
error
=
transaction
.
error
{
log
.
error
(
"SKPaymentTransactionStateFailedError:
\(
error
)
"
)
}
else
{
log
.
error
(
"SKPaymentTransactionStateFailedError: unknown error"
)
}
delegate
?
.
inAppStoreManager
(
self
,
purchaseFailedFor
:
transaction
)
SKPaymentQueue
.
default
()
.
finishTransaction
(
transaction
)
case
.
restored
:
delegate
?
.
inAppStoreManager
(
self
,
restoredCompletedForProductId
:
transaction
.
payment
.
productIdentifier
)
SKPaymentQueue
.
default
()
.
finishTransaction
(
transaction
)
default
:
break
}
}
}
func
paymentQueue
(
_
queue
:
SKPaymentQueue
,
updatedDownloads
downloads
:
[
SKDownload
])
{
log
.
debug
(
"paymentQueue:updatedDownloads"
)
}
// MARK: - SKPaymentTransactionObserver - optional
func
paymentQueue
(
_
queue
:
SKPaymentQueue
,
removedTransactions
transactions
:
[
SKPaymentTransaction
])
{
log
.
debug
(
"paymentQueue:removedTransactions"
)
}
func
paymentQueue
(
_
queue
:
SKPaymentQueue
,
restoreCompletedTransactionsFailedWithError
error
:
Error
)
{
log
.
error
(
"paymentQueue:restoreCompletedTransactionsFailedWithError:
\(
error
)
"
)
delegate
?
.
inAppStoreManager
(
self
,
restoreFailedWithError
:
error
)
}
func
paymentQueueRestoreCompletedTransactionsFinished
(
_
queue
:
SKPaymentQueue
)
{
log
.
info
(
"paymentQueueRestoreCompletedTransactionsFinished productId:
\(
queue
.
transactions
.
first
?
.
payment
.
productIdentifier
??
"None"
)
"
)
if
let
transaction
=
queue
.
transactions
.
first
,
kInAppOneWeatherProId
==
transaction
.
payment
.
productIdentifier
{
delegate
?
.
inAppStoreManager
(
self
,
restoredCompletedForProductId
:
transaction
.
payment
.
productIdentifier
)
}
else
{
delegate
?
.
inAppStoreManager
(
self
,
restoreFailedWithMessage
:
"inapp.restoration.error.no.purchases"
.
localized
())
}
}
}
// MARK: - SKRequestDelegate
extension
OLInAppStoreManager
:
SKRequestDelegate
{
func
requestDidFinish
(
_
request
:
SKRequest
)
{
log
.
debug
(
"requestDidFinish"
)
}
func
request
(
_
request
:
SKRequest
,
didFailWithError
error
:
Error
)
{
log
.
error
(
"Failed to connect with error:
\(
error
)
"
)
}
}
1Weather/Resources/en.lproj/Localizable.strings
View file @
4d5d2068
...
@@ -204,3 +204,12 @@
...
@@ -204,3 +204,12 @@
"health.airquality.status.unhealthy" = "Unhealthy";
"health.airquality.status.unhealthy" = "Unhealthy";
"health.airquality.status.veryUnhealthy" = "Very Unhealthy";
"health.airquality.status.veryUnhealthy" = "Very Unhealthy";
"health.airquality.status.hazardous" = "Hazardous";
"health.airquality.status.hazardous" = "Hazardous";
// InApp
"inapp.alert.prohibited.title" = "Prohibited";
"inapp.error.parental.control.cant.make.purchase" = "Parental Control is enabled, cannot make a purchase!";
"inapp.error.parental.control.cant.store" = "Parental Control is enabled, cannot store!";
"inapp.alert.product.not.available.title" = "Product Not Available";
"inapp.alert.product.not.available.text" = "Please contact support.";
"inapp.restoration.error.no.purchases" = "There are no purchases to restore";
"inapp.alert.ok" = "Ok";
1Weather/StuffThatIsPresentInTheMainProject.swift
View file @
4d5d2068
...
@@ -23,8 +23,8 @@ let DOWN_ARROW = "\u{2193}"
...
@@ -23,8 +23,8 @@ let DOWN_ARROW = "\u{2193}"
// isPro
// isPro
func
isAppPro
()
->
Bool
{
func
isAppPro
()
->
Bool
{
if
let
metricsLog
=
UserDefaults
.
standard
.
dictionary
(
forKey
:
kOLAppMetricsKey
)
,
let
event
=
metricsLog
[
kEventInAppPurchasedCompleted
]
{
if
let
metricsLog
=
UserDefaults
.
standard
.
dictionary
(
forKey
:
kOLAppMetricsKey
)
{
return
event
!=
nil
return
metricsLog
[
kEventInAppPurchasedCompleted
]
!=
nil
}
}
return
false
return
false
}
}
...
...
1Weather/UI/View controllers/NWSAlert/Cells/NWSAlertCellFactory.swift
View file @
4d5d2068
...
@@ -42,7 +42,12 @@ fileprivate struct HeaderSection: NWSAlertTableViewSection {
...
@@ -42,7 +42,12 @@ fileprivate struct HeaderSection: NWSAlertTableViewSection {
fileprivate
struct
ExtendedInfoSection
:
NWSAlertTableViewSection
{
fileprivate
struct
ExtendedInfoSection
:
NWSAlertTableViewSection
{
private
var
alert
:
NWSAlert
private
var
alert
:
NWSAlert
private
let
countOfAds
=
1
private
var
countOfAds
:
Int
{
if
!
isAppPro
()
&&
AdConfigManager
.
shared
.
adConfig
.
adsEnabled
{
return
1
}
return
0
}
init
(
alert
:
NWSAlert
)
{
init
(
alert
:
NWSAlert
)
{
self
.
alert
=
alert
self
.
alert
=
alert
...
@@ -57,6 +62,9 @@ fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection {
...
@@ -57,6 +62,9 @@ fileprivate struct ExtendedInfoSection: NWSAlertTableViewSection {
}
}
func
type
(
forRow
row
:
Int
)
->
NWSAlertCellType
{
func
type
(
forRow
row
:
Int
)
->
NWSAlertCellType
{
guard
countOfAds
>
0
else
{
return
.
extendedInfoBlock
}
if
numberOfRows
==
1
{
if
numberOfRows
==
1
{
return
.
ad
return
.
ad
}
}
...
...
1Weather/UI/View controllers/Today/Cells/TodayCellFactory.swift
View file @
4d5d2068
...
@@ -188,7 +188,7 @@ class TodayCellFactory: CellFactoryProtocol {
...
@@ -188,7 +188,7 @@ class TodayCellFactory: CellFactoryProtocol {
private
func
setupHiddenRows
()
{
private
func
setupHiddenRows
()
{
var
rowsToHide
=
Set
<
TodayCellType
>
()
var
rowsToHide
=
Set
<
TodayCellType
>
()
if
!
AdConfigManager
.
shared
.
adConfig
.
adsEnabled
{
if
isAppPro
()
||
!
AdConfigManager
.
shared
.
adConfig
.
adsEnabled
{
rowsToHide
.
insert
(
.
ad
)
rowsToHide
.
insert
(
.
ad
)
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment