@tyrads.com/tyrads-sdk 3.1.0-beta.0 → 3.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/tyradssdk/TyradsSdkModule.kt +130 -46
- package/ios/Tyrads/AcmoAssets.swift +14 -0
- package/ios/Tyrads/ApiHeaders.swift +1 -0
- package/ios/Tyrads/Tyrads.swift +184 -57
- package/ios/Tyrads/WebViewController.swift +27 -3
- package/ios/Tyrads/core/utils/AcmoKeyNames.swift +29 -0
- package/ios/Tyrads/core/utils/ColorExtension.swift +55 -0
- package/ios/Tyrads/core/utils/Services/LocalizationService.swift +175 -0
- package/ios/Tyrads/helpers/device_details.swift +148 -46
- package/ios/Tyrads/legal/AcmoPrivacyPage.swift +353 -0
- package/ios/Tyrads/legal/PrivacyPageController.swift +31 -0
- package/ios/Tyrads/user/AcmoUserUpdatePage.swift +302 -0
- package/ios/Tyrads/user/AcmoUsersUpdateController.swift +26 -0
- package/ios/Tyrads/user/Repository.swift +89 -0
- package/ios/TyradsSdk.mm +15 -3
- package/ios/TyradsSdk.swift +101 -46
- package/lib/commonjs/acmo/core/helpers/native_methods.js +37 -0
- package/lib/commonjs/acmo/core/helpers/native_methods.js.map +1 -0
- package/lib/commonjs/acmo/core/helpers/numeral.js +19 -0
- package/lib/commonjs/acmo/core/helpers/numeral.js.map +1 -0
- package/lib/commonjs/acmo/core/services/localization_service.js +164 -0
- package/lib/commonjs/acmo/core/services/localization_service.js.map +1 -0
- package/lib/commonjs/acmo/core/storage/storage.js +15 -1
- package/lib/commonjs/acmo/core/storage/storage.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/components/active_offers_button.js +5 -2
- package/lib/commonjs/acmo/modules/dashboard/components/active_offers_button.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/components/offer_card.js +3 -4
- package/lib/commonjs/acmo/modules/dashboard/components/offer_card.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/components/offer_list_item.js +12 -6
- package/lib/commonjs/acmo/modules/dashboard/components/offer_list_item.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/components/premium_empty_widget.js +6 -2
- package/lib/commonjs/acmo/modules/dashboard/components/premium_empty_widget.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/components/premium_header.js +4 -4
- package/lib/commonjs/acmo/modules/dashboard/components/premium_header.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/components/premium_loading.js +4 -11
- package/lib/commonjs/acmo/modules/dashboard/components/premium_loading.js.map +1 -1
- package/lib/commonjs/acmo/modules/dashboard/repository.js +1 -1
- package/lib/commonjs/acmo/modules/dashboard/top_offers.js +15 -0
- package/lib/commonjs/acmo/modules/dashboard/top_offers.js.map +1 -1
- package/lib/commonjs/acmo/modules/localization/localization_context.js +56 -0
- package/lib/commonjs/acmo/modules/localization/localization_context.js.map +1 -0
- package/lib/commonjs/index.js +39 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/acmo/core/helpers/native_methods.js +33 -0
- package/lib/module/acmo/core/helpers/native_methods.js.map +1 -0
- package/lib/module/acmo/core/helpers/numeral.js +14 -0
- package/lib/module/acmo/core/helpers/numeral.js.map +1 -0
- package/lib/module/acmo/core/services/localization_service.js +159 -0
- package/lib/module/acmo/core/services/localization_service.js.map +1 -0
- package/lib/module/acmo/core/storage/storage.js +13 -0
- package/lib/module/acmo/core/storage/storage.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/components/active_offers_button.js +5 -2
- package/lib/module/acmo/modules/dashboard/components/active_offers_button.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/components/offer_card.js +3 -3
- package/lib/module/acmo/modules/dashboard/components/offer_card.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/components/offer_list_item.js +12 -6
- package/lib/module/acmo/modules/dashboard/components/offer_list_item.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/components/premium_empty_widget.js +6 -2
- package/lib/module/acmo/modules/dashboard/components/premium_empty_widget.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/components/premium_header.js +4 -4
- package/lib/module/acmo/modules/dashboard/components/premium_header.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/components/premium_loading.js +5 -12
- package/lib/module/acmo/modules/dashboard/components/premium_loading.js.map +1 -1
- package/lib/module/acmo/modules/dashboard/repository.js +1 -1
- package/lib/module/acmo/modules/dashboard/top_offers.js +15 -0
- package/lib/module/acmo/modules/dashboard/top_offers.js.map +1 -1
- package/lib/module/acmo/modules/localization/localization_context.js +45 -0
- package/lib/module/acmo/modules/localization/localization_context.js.map +1 -0
- package/lib/module/index.js +38 -6
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/acmo/core/helpers/native_methods.d.ts +6 -0
- package/lib/typescript/commonjs/src/acmo/core/helpers/native_methods.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/acmo/core/helpers/numeral.d.ts +2 -0
- package/lib/typescript/commonjs/src/acmo/core/helpers/numeral.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/acmo/core/services/localization_service.d.ts +18 -0
- package/lib/typescript/commonjs/src/acmo/core/services/localization_service.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/acmo/core/storage/storage.d.ts +1 -0
- package/lib/typescript/commonjs/src/acmo/core/storage/storage.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/active_offers_button.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_card.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/offer_list_item.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_header.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_loading.d.ts +0 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/components/premium_loading.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/dashboard/top_offers.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/acmo/modules/localization/localization_context.d.ts +14 -0
- package/lib/typescript/commonjs/src/acmo/modules/localization/localization_context.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +4 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/core/helpers/native_methods.d.ts +6 -0
- package/lib/typescript/module/src/acmo/core/helpers/native_methods.d.ts.map +1 -0
- package/lib/typescript/module/src/acmo/core/helpers/numeral.d.ts +2 -0
- package/lib/typescript/module/src/acmo/core/helpers/numeral.d.ts.map +1 -0
- package/lib/typescript/module/src/acmo/core/services/localization_service.d.ts +18 -0
- package/lib/typescript/module/src/acmo/core/services/localization_service.d.ts.map +1 -0
- package/lib/typescript/module/src/acmo/core/storage/storage.d.ts +1 -0
- package/lib/typescript/module/src/acmo/core/storage/storage.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/active_offers_button.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_card.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/offer_list_item.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_empty_widget.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_header.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_loading.d.ts +0 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/components/premium_loading.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/dashboard/top_offers.d.ts.map +1 -1
- package/lib/typescript/module/src/acmo/modules/localization/localization_context.d.ts +14 -0
- package/lib/typescript/module/src/acmo/modules/localization/localization_context.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +4 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +2 -6
- package/src/acmo/core/helpers/native_methods.ts +43 -0
- package/src/acmo/core/helpers/numeral.ts +14 -0
- package/src/acmo/core/services/localization_service.ts +200 -0
- package/src/acmo/core/storage/storage.ts +14 -0
- package/src/acmo/modules/dashboard/components/active_offers_button.tsx +3 -2
- package/src/acmo/modules/dashboard/components/offer_card.tsx +3 -3
- package/src/acmo/modules/dashboard/components/offer_list_item.tsx +8 -5
- package/src/acmo/modules/dashboard/components/premium_empty_widget.tsx +5 -2
- package/src/acmo/modules/dashboard/components/premium_header.tsx +6 -5
- package/src/acmo/modules/dashboard/components/premium_loading.tsx +2 -8
- package/src/acmo/modules/dashboard/repository.ts +1 -1
- package/src/acmo/modules/dashboard/top_offers.tsx +18 -3
- package/src/acmo/modules/localization/localization_context.tsx +52 -0
- package/src/index.tsx +63 -18
- package/lib/commonjs/i18n.js +0 -112
- package/lib/commonjs/i18n.js.map +0 -1
- package/lib/module/i18n.js +0 -107
- package/lib/module/i18n.js.map +0 -1
- package/lib/typescript/commonjs/src/i18n.d.ts +0 -3
- package/lib/typescript/commonjs/src/i18n.d.ts.map +0 -1
- package/lib/typescript/module/src/i18n.d.ts +0 -3
- package/lib/typescript/module/src/i18n.d.ts.map +0 -1
- package/src/i18n.ts +0 -115
@@ -0,0 +1,302 @@
|
|
1
|
+
//
|
2
|
+
// AcmoUserUpdatePage.swift
|
3
|
+
// Pods
|
4
|
+
//
|
5
|
+
// Created by Basharat Mehdi on 30/09/25.
|
6
|
+
//
|
7
|
+
|
8
|
+
import SwiftUI
|
9
|
+
|
10
|
+
struct AcmoUsersUpdatePage: View {
|
11
|
+
@Environment(\.presentationMode) var presentationMode
|
12
|
+
|
13
|
+
var localization: LocalizationService = LocalizationService.shared
|
14
|
+
|
15
|
+
var onSubmit: (() -> Void)?
|
16
|
+
|
17
|
+
public init(onSubmit: (() -> Void)? = nil) {
|
18
|
+
self.onSubmit = onSubmit
|
19
|
+
}
|
20
|
+
|
21
|
+
@State private var selectedGender: String? = nil
|
22
|
+
@State private var selectedAge: String = "18"
|
23
|
+
@State private var isSubmitting = false
|
24
|
+
@State private var showError = false
|
25
|
+
@State private var errorMessage = ""
|
26
|
+
|
27
|
+
var body: some View {
|
28
|
+
ZStack{
|
29
|
+
VStack {
|
30
|
+
HStack {
|
31
|
+
Spacer()
|
32
|
+
Button(action: {
|
33
|
+
Tyrads.instance.setSkipUserUpdate(true)
|
34
|
+
Tyrads.instance.setNewUser(false)
|
35
|
+
presentationMode.wrappedValue.dismiss()
|
36
|
+
onSubmit?()
|
37
|
+
}) {
|
38
|
+
Text(localization.translate("data.shared.button.skip"))
|
39
|
+
.font(.system(size: 14))
|
40
|
+
.fontWeight(.semibold)
|
41
|
+
.frame(minWidth: 80, minHeight: 35)
|
42
|
+
.foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
|
43
|
+
.overlay(
|
44
|
+
RoundedRectangle(cornerRadius: 50)
|
45
|
+
.stroke(Color(hex: Tyrads.instance.mainColor ?? "#000000"), lineWidth: 2)
|
46
|
+
).padding(.horizontal, 16)
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
ScrollView {
|
51
|
+
VStack(spacing: 40) {
|
52
|
+
Text(localization.translate("data.initialization.userInfo.title"))
|
53
|
+
.font(.system(size: 16, weight: .semibold))
|
54
|
+
.multilineTextAlignment(.center)
|
55
|
+
.foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
|
56
|
+
Spacer()
|
57
|
+
.frame(height: 20)
|
58
|
+
|
59
|
+
VStack(spacing: 25) {
|
60
|
+
Text(localization.translate(
|
61
|
+
"data.initialization.userInfo.chooseGender.label"))
|
62
|
+
.font(.system(size: 16, weight: .semibold))
|
63
|
+
.foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
|
64
|
+
|
65
|
+
GenderSelectView(selectedGender: $selectedGender, localization: localization)
|
66
|
+
Spacer().frame(height: 50)
|
67
|
+
|
68
|
+
Text(localization.translate(
|
69
|
+
"data.initialization.userInfo.chooseAge.label"))
|
70
|
+
.font(.system(size: 16, weight: .semibold))
|
71
|
+
.foregroundColor(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
|
72
|
+
|
73
|
+
AgeSelectView(selectedAge: $selectedAge)
|
74
|
+
}
|
75
|
+
|
76
|
+
Spacer().frame(height: 10)
|
77
|
+
|
78
|
+
Button(action: {
|
79
|
+
submit()
|
80
|
+
}) {
|
81
|
+
Text(isSubmitting ? "Submitting..." : localization.translate(
|
82
|
+
"data.initialization.userInfo.cta.continue"))
|
83
|
+
.font(.system(size: 15, weight: .semibold))
|
84
|
+
.foregroundColor(.white)
|
85
|
+
.frame(maxWidth: .infinity)
|
86
|
+
.frame(height: 44)
|
87
|
+
.background(Color(hex: Tyrads.instance.mainColor ?? "#000000"))
|
88
|
+
.cornerRadius(4)
|
89
|
+
}
|
90
|
+
.disabled(isSubmitting)
|
91
|
+
}
|
92
|
+
.padding(.horizontal, 20)
|
93
|
+
}
|
94
|
+
}
|
95
|
+
.alert(isPresented: $showError) {
|
96
|
+
Alert(title: Text("Error"), message: Text(errorMessage), dismissButton: .default(Text("OK")))
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
}
|
101
|
+
func submit() {
|
102
|
+
guard let gender = selectedGender, !gender.isEmpty else {
|
103
|
+
errorMessage = "Please select gender to proceed."
|
104
|
+
showError = true
|
105
|
+
return
|
106
|
+
}
|
107
|
+
|
108
|
+
isSubmitting = true
|
109
|
+
errorMessage = ""
|
110
|
+
showError = false
|
111
|
+
|
112
|
+
Task {
|
113
|
+
do {
|
114
|
+
try await UserRepository.shared.updateUser(
|
115
|
+
userID: Tyrads.instance.publisherUserID,
|
116
|
+
gender: gender,
|
117
|
+
age: selectedAge
|
118
|
+
)
|
119
|
+
|
120
|
+
await MainActor.run {
|
121
|
+
self.isSubmitting = false
|
122
|
+
Tyrads.instance.setNewUser(false)
|
123
|
+
self.presentationMode.wrappedValue.dismiss()
|
124
|
+
self.onSubmit?()
|
125
|
+
}
|
126
|
+
|
127
|
+
} catch {
|
128
|
+
await MainActor.run {
|
129
|
+
self.isSubmitting = false
|
130
|
+
self.errorMessage = "Failed to update user data: \(error.localizedDescription)"
|
131
|
+
self.showError = true
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
struct GenderSelectView: View {
|
139
|
+
@Binding var selectedGender: String?
|
140
|
+
let localization: LocalizationService
|
141
|
+
|
142
|
+
var body: some View {
|
143
|
+
HStack(spacing: 20) {
|
144
|
+
GenderButton(title: localization.translate("data.initialization.userInfo.gender.male"), selectedGender: $selectedGender,
|
145
|
+
localization: localization
|
146
|
+
)
|
147
|
+
GenderButton(title: localization.translate("data.initialization.userInfo.gender.female"), selectedGender: $selectedGender, localization: localization)
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
struct GenderButton: View {
|
153
|
+
|
154
|
+
func decodeBase64Image(_ base64: String) -> UIImage? {
|
155
|
+
guard let data = Data(base64Encoded: base64) else { return nil }
|
156
|
+
return UIImage(data: data)
|
157
|
+
}
|
158
|
+
let title: String
|
159
|
+
@Binding var selectedGender: String?
|
160
|
+
let localization: LocalizationService
|
161
|
+
|
162
|
+
var body: some View {
|
163
|
+
Button(action: {
|
164
|
+
selectedGender = title
|
165
|
+
}) {
|
166
|
+
VStack{
|
167
|
+
if let image = decodeBase64Image(title == localization.translate("data.initialization.userInfo.gender.male") ? AcmoAssets.maleBase64 : AcmoAssets.femaleBase64) {
|
168
|
+
Image(uiImage: image)
|
169
|
+
.renderingMode(.template)
|
170
|
+
.resizable()
|
171
|
+
.scaledToFit()
|
172
|
+
.foregroundColor(selectedGender == title ? .white : Color(hex: "#667085"))
|
173
|
+
.frame(width: 24, height: 24)
|
174
|
+
}
|
175
|
+
Text(title)
|
176
|
+
.foregroundColor(selectedGender == title ? .white : Color(hex: "#667085"))
|
177
|
+
}
|
178
|
+
}
|
179
|
+
.frame(width: 100, height: 102)
|
180
|
+
.background(selectedGender == title ? Color(hex: Tyrads.instance.mainColor ?? "#000000") : Color.white)
|
181
|
+
.cornerRadius(4)
|
182
|
+
.shadow(color: Color.black.opacity(0.25), radius: 4, x: 0, y: 1)
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
struct AgeSelectView: View {
|
187
|
+
@Binding var selectedAge: String
|
188
|
+
private let ages = Array(13..<109).map { String($0) }
|
189
|
+
|
190
|
+
var body: some View {
|
191
|
+
HorizontalAgePicker(selectedAge: $selectedAge)
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
struct HorizontalAgePicker: View {
|
196
|
+
@Binding var selectedAge: String
|
197
|
+
private let ages = Array(13...108).map { String($0) }
|
198
|
+
|
199
|
+
var body: some View {
|
200
|
+
GeometryReader { geometry in
|
201
|
+
let screenCenter = geometry.size.width / 2
|
202
|
+
|
203
|
+
if #available(iOS 14.0, *) {
|
204
|
+
ScrollViewReader{ proxy in
|
205
|
+
ScrollView(.horizontal, showsIndicators: false) {
|
206
|
+
HStack(spacing: 4) {
|
207
|
+
Spacer()
|
208
|
+
.frame(width: screenCenter - 30)
|
209
|
+
|
210
|
+
ForEach(ages, id: \.self) { age in
|
211
|
+
GeometryReader { geo in
|
212
|
+
let itemCenter = geo.frame(in: .global).midX
|
213
|
+
let distance = abs(itemCenter - screenCenter)
|
214
|
+
let scale = max(0.8, 1.2 - distance / 200)
|
215
|
+
|
216
|
+
var fontSize: CGFloat {
|
217
|
+
selectedAge == age ? 30 : 17
|
218
|
+
}
|
219
|
+
|
220
|
+
var fontWeight: Font.Weight {
|
221
|
+
selectedAge == age ? .semibold : .regular
|
222
|
+
}
|
223
|
+
|
224
|
+
Text(age)
|
225
|
+
.font(.system(size: fontSize, weight: fontWeight))
|
226
|
+
.frame(width: 90, height: 58)
|
227
|
+
.background(selectedAge == age ? Color(hex: "#F6F6F6") : .clear)
|
228
|
+
.foregroundColor(selectedAge == age ? Color(hex: Tyrads.instance.mainColor ?? "#FFFFFF") : .gray)
|
229
|
+
.cornerRadius(10)
|
230
|
+
.animation(.easeOut(duration: 0.2), value: scale)
|
231
|
+
.onAppear {
|
232
|
+
DispatchQueue.main.async {
|
233
|
+
proxy.scrollTo("18", anchor: .center)
|
234
|
+
}
|
235
|
+
}
|
236
|
+
.onChange(of: distance) { _ in
|
237
|
+
if distance < 20 {
|
238
|
+
if selectedAge != age {
|
239
|
+
DispatchQueue.main.async {
|
240
|
+
selectedAge = age
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
}
|
247
|
+
.frame(width: 60, height: 74)
|
248
|
+
}
|
249
|
+
|
250
|
+
Spacer()
|
251
|
+
.frame(width: screenCenter - 30)
|
252
|
+
}
|
253
|
+
}
|
254
|
+
}
|
255
|
+
} else {
|
256
|
+
ScrollView(.horizontal, showsIndicators: false) {
|
257
|
+
HStack(spacing: 4) {
|
258
|
+
Spacer()
|
259
|
+
.frame(width: screenCenter - 30)
|
260
|
+
|
261
|
+
ForEach(ages, id: \.self) { age in
|
262
|
+
GeometryReader { geo in
|
263
|
+
let itemCenter = geo.frame(in: .global).midX
|
264
|
+
let distance = abs(itemCenter - screenCenter)
|
265
|
+
let scale = max(0.8, 1.2 - distance / 200)
|
266
|
+
|
267
|
+
var fontSize: CGFloat {
|
268
|
+
selectedAge == age ? 30 : 17
|
269
|
+
}
|
270
|
+
|
271
|
+
var fontWeight: Font.Weight {
|
272
|
+
selectedAge == age ? .semibold : .regular
|
273
|
+
}
|
274
|
+
Text(age)
|
275
|
+
.font(.system(size: selectedAge == age ? 30 : 20, weight: .semibold))
|
276
|
+
.frame(width: 90, height: 58)
|
277
|
+
.background(selectedAge == age ? Color("#F6F6F6") : .clear)
|
278
|
+
.foregroundColor(selectedAge == age ? Color(hex: Tyrads.instance.mainColor ?? "#FFFFFF") : .black)
|
279
|
+
.cornerRadius(10)
|
280
|
+
.animation(.easeOut(duration: 0.2), value: scale)
|
281
|
+
.onAppear {
|
282
|
+
if age == ages.first {
|
283
|
+
selectedAge = age
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
}
|
288
|
+
.frame(width: 60, height: 74)
|
289
|
+
}
|
290
|
+
|
291
|
+
Spacer()
|
292
|
+
.frame(width: screenCenter - 30)
|
293
|
+
}
|
294
|
+
|
295
|
+
}
|
296
|
+
}
|
297
|
+
}
|
298
|
+
.frame(height: 100)
|
299
|
+
}
|
300
|
+
}
|
301
|
+
|
302
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
//
|
2
|
+
// AcmoUserUpdatePageController.swift
|
3
|
+
// Pods
|
4
|
+
//
|
5
|
+
// Created by Basharat Mehdi on 30/09/25.
|
6
|
+
//
|
7
|
+
|
8
|
+
import UIKit
|
9
|
+
import SwiftUI
|
10
|
+
|
11
|
+
public typealias UserUpdateCompletion = () -> Void
|
12
|
+
class AcmoUsersUpdateController: UIHostingController<AcmoUsersUpdatePage> {
|
13
|
+
public init(onSubmit: UserUpdateCompletion? = nil) {
|
14
|
+
let rootView = AcmoUsersUpdatePage(onSubmit: onSubmit)
|
15
|
+
super.init(rootView: rootView)
|
16
|
+
self.modalPresentationStyle = .fullScreen
|
17
|
+
}
|
18
|
+
|
19
|
+
@MainActor required dynamic init?(coder aDecoder: NSCoder) {
|
20
|
+
fatalError("init(coder:) has not been implemented")
|
21
|
+
}
|
22
|
+
|
23
|
+
override func viewWillDisappear(_ animated: Bool) {
|
24
|
+
super.viewWillDisappear(animated)
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
//
|
2
|
+
// Repository.swift
|
3
|
+
// Pods
|
4
|
+
//
|
5
|
+
// Created by Basharat Mehdi on 01/10/25.
|
6
|
+
//
|
7
|
+
|
8
|
+
import Foundation
|
9
|
+
import UIKit
|
10
|
+
|
11
|
+
public class UserRepository {
|
12
|
+
|
13
|
+
public static let shared = UserRepository()
|
14
|
+
|
15
|
+
private init() {}
|
16
|
+
|
17
|
+
public func updateUser(userID: String, gender: String, age: String) async throws {
|
18
|
+
let sdk = Tyrads.instance
|
19
|
+
|
20
|
+
guard let ageInt = Int(age) else {
|
21
|
+
print("ERROR: Failed to convert age string '\(age)' to integer.")
|
22
|
+
throw NSError(domain: "TyradsSdk", code: 4, userInfo: [NSLocalizedDescriptionKey: "Invalid age format."])
|
23
|
+
}
|
24
|
+
|
25
|
+
let fd: [String: Any] = [
|
26
|
+
"gender": gender == "Male" ? 1 : 2,
|
27
|
+
"age": ageInt,
|
28
|
+
]
|
29
|
+
|
30
|
+
let fullURLString = AcmoConfig.BASE_URL + "update-user"
|
31
|
+
|
32
|
+
print("--- USER UPDATE REQUEST ---")
|
33
|
+
print("UserID: \(userID)")
|
34
|
+
print("URL: \(fullURLString)")
|
35
|
+
print("Data Sent: \(fd)")
|
36
|
+
|
37
|
+
let requestBody = sdk.isSecure && !(sdk.encKey ?? "").isEmpty ? try AcmoEncrypt(sdk.encKey!).encryptDataAESGCM(data: fd) : fd
|
38
|
+
|
39
|
+
guard let url = URL(string: fullURLString) else {
|
40
|
+
throw NSError(domain: "TyradsSdk", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL for user update"])
|
41
|
+
}
|
42
|
+
|
43
|
+
var request = URLRequest(url: url)
|
44
|
+
request.httpMethod = "PUT"
|
45
|
+
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
46
|
+
request.setValue(sdk.apiKey, forHTTPHeaderField: "X-API-Key")
|
47
|
+
request.setValue(sdk.apiSecret, forHTTPHeaderField: "X-API-Secret")
|
48
|
+
request.setValue(userID, forHTTPHeaderField: "X-User-ID")
|
49
|
+
request.setValue(AcmoConfig.SDK_PLATFORM, forHTTPHeaderField: "X-SDK-Platform")
|
50
|
+
request.setValue(AcmoConfig.SDK_VERSION, forHTTPHeaderField: "X-SDK-Version")
|
51
|
+
request.setValue(sdk.isSecure ? "BASIC" : "PLAIN", forHTTPHeaderField: "X-Secure-Mode")
|
52
|
+
|
53
|
+
print("X-API-Key: \(sdk.apiKey)")
|
54
|
+
print("X-API-Secret: \(sdk.apiSecret)")
|
55
|
+
print("X-Publisher-User-Id: \(userID)")
|
56
|
+
print("Request Body: \(requestBody)")
|
57
|
+
|
58
|
+
do {
|
59
|
+
request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
|
60
|
+
} catch {
|
61
|
+
print("ERROR: Failed to serialize request body: \(error)")
|
62
|
+
throw error
|
63
|
+
}
|
64
|
+
|
65
|
+
let (data, response) = try await URLSession.shared.data(for: request)
|
66
|
+
|
67
|
+
let responseString = String(data: data, encoding: .utf8) ?? "No readable response data"
|
68
|
+
|
69
|
+
guard let httpResponse = response as? HTTPURLResponse else {
|
70
|
+
print("ERROR: Response was not HTTPURLResponse.")
|
71
|
+
throw NSError(domain: "TyradsSdk", code: 0, userInfo: [NSLocalizedDescriptionKey: "Non-HTTP response received."])
|
72
|
+
}
|
73
|
+
|
74
|
+
print("Response Status Code: \(httpResponse.statusCode)")
|
75
|
+
print("Response Body: \(responseString)")
|
76
|
+
|
77
|
+
guard (200...299).contains(httpResponse.statusCode) else {
|
78
|
+
let statusCode = httpResponse.statusCode
|
79
|
+
sdk.log("User update failed with status: \(statusCode)")
|
80
|
+
|
81
|
+
let fullErrorDescription = "Failed to update user demographics."
|
82
|
+
throw NSError(domain: "TyradsSdk", code: statusCode,
|
83
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to update user demographics."])
|
84
|
+
}
|
85
|
+
|
86
|
+
print("User has been updated please check")
|
87
|
+
sdk.log("User update successful.")
|
88
|
+
}
|
89
|
+
}
|
package/ios/TyradsSdk.mm
CHANGED
@@ -2,9 +2,13 @@
|
|
2
2
|
|
3
3
|
@interface RCT_EXTERN_MODULE(TyradsSdk, NSObject)
|
4
4
|
|
5
|
-
RCT_EXTERN_METHOD(
|
6
|
-
|
7
|
-
|
5
|
+
RCT_EXTERN_METHOD(startObserving)
|
6
|
+
RCT_EXTERN_METHOD(stopObserving)
|
7
|
+
RCT_EXTERN_METHOD(init:(NSString *)apiKey
|
8
|
+
secretKey:(NSString *)secretKey
|
9
|
+
encKey:(NSString * _Nullable)encKey
|
10
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
11
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
8
12
|
// RCT_EXTERN_METHOD(loginUser:(NSString *)userId)
|
9
13
|
RCT_EXTERN_METHOD(loginUser:(NSString *)userId
|
10
14
|
resolver:(RCTPromiseResolveBlock)resolve
|
@@ -18,5 +22,13 @@ RCT_EXTERN_METHOD(showOfferDetails:(NSInteger)launchMode
|
|
18
22
|
campaignID:(NSInteger)campaignID
|
19
23
|
resolver:(RCTPromiseResolveBlock)resolve
|
20
24
|
rejecter:(RCTPromiseRejectBlock)reject)
|
25
|
+
RCT_EXTERN_METHOD(changeLanguage:(NSString *)lang
|
26
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
27
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
28
|
+
RCT_EXTERN_METHOD(isPrivacyAccepted:(RCTPromiseResolveBlock)resolve
|
29
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
30
|
+
RCT_EXTERN_METHOD(checkOnboardingProcess:(RCTPromiseResolveBlock)resolve
|
31
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
32
|
+
|
21
33
|
|
22
34
|
@end
|
package/ios/TyradsSdk.swift
CHANGED
@@ -1,62 +1,117 @@
|
|
1
1
|
import Foundation
|
2
2
|
import UIKit
|
3
|
+
import Combine
|
4
|
+
import React
|
3
5
|
|
4
6
|
|
5
7
|
@objc(TyradsSdk)
|
6
|
-
class TyradsSdk:
|
7
|
-
|
8
|
+
class TyradsSdk: RCTEventEmitter {
|
9
|
+
|
10
|
+
private var cancellable: AnyCancellable?
|
11
|
+
|
12
|
+
override func startObserving() {
|
13
|
+
cancellable = Tyrads.instance.languagePublisher
|
14
|
+
.sink { [weak self] lang in
|
15
|
+
self?.sendEvent(withName: "LanguageChanged", body: lang)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
override func stopObserving() {
|
20
|
+
cancellable?.cancel()
|
21
|
+
cancellable = nil
|
22
|
+
}
|
23
|
+
|
24
|
+
override func supportedEvents() -> [String]! {
|
25
|
+
return ["LanguageChanged"]
|
26
|
+
}
|
27
|
+
|
8
28
|
@objc
|
9
|
-
func `init`(_ apiKey: String, secretKey: String, encKey: String? = nil) {
|
29
|
+
func `init`(_ apiKey: String, secretKey: String, encKey: String? = nil, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
10
30
|
NSLog("TyradsModule: init called with apiKey: \(apiKey) and secretKey: \(secretKey)")
|
11
|
-
|
31
|
+
Task {
|
32
|
+
do{
|
33
|
+
let locale = await Tyrads.instance.configure(apiKey: apiKey, secretKey: secretKey, encKey: encKey)
|
34
|
+
let result: [String: Any] = [
|
35
|
+
"success": true,
|
36
|
+
"languageCode": locale
|
37
|
+
]
|
38
|
+
resolve (result)
|
39
|
+
} catch {
|
40
|
+
reject("INIT_FAILED", "Failed to initialize", error)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
12
44
|
}
|
13
|
-
|
45
|
+
|
14
46
|
@objc
|
15
47
|
func loginUser(_ userId: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
48
|
+
NSLog("TyradsModule: loginUser called with userId: \(userId)")
|
49
|
+
|
50
|
+
Task {
|
51
|
+
do {
|
52
|
+
guard let apiHeaders = try await Tyrads.instance.loginUser(userId) else {
|
53
|
+
reject("LOGIN_ERROR", "Login failed or returned nil headers", nil)
|
54
|
+
return
|
55
|
+
}
|
56
|
+
|
57
|
+
let result: [String: Any] = [
|
58
|
+
"xApiKey": apiHeaders.xApiKey,
|
59
|
+
"xApiSecret": apiHeaders.xApiSecret,
|
60
|
+
"xUserId": apiHeaders.xUserId,
|
61
|
+
"xSdkPlatform": apiHeaders.xSdkPlatform ?? "",
|
62
|
+
"xSdkVersion": apiHeaders.xSdkVersion ?? "",
|
63
|
+
"userAgent": apiHeaders.userAgent,
|
64
|
+
"languageCode": apiHeaders.languageCode,
|
65
|
+
"premiumColor": apiHeaders.premiumColor,
|
66
|
+
"headerColor": apiHeaders.headerColor,
|
67
|
+
"mainColor": apiHeaders.mainColor,
|
68
|
+
"privacyAccepted": apiHeaders.privacyAccepted
|
69
|
+
]
|
70
|
+
|
71
|
+
resolve(result)
|
72
|
+
} catch {
|
73
|
+
reject("LOGIN_ERROR", error.localizedDescription, error)
|
42
74
|
}
|
75
|
+
}
|
43
76
|
}
|
44
|
-
|
77
|
+
|
45
78
|
|
46
79
|
@objc(showOffers:route:resolver:rejecter:)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
80
|
+
func showOffers(_ launchMode: Int, route: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
81
|
+
Task {
|
82
|
+
await Tyrads.instance.showOffers(launchMode, route: route, campaignID: nil)
|
83
|
+
resolve(nil)
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
@objc(showOfferDetails:route:campaignID:resolver:rejecter:)
|
88
|
+
func showOfferDetails(_ launchMode: Int, route: String?, campaignID: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
89
|
+
Task {
|
90
|
+
await Tyrads.instance.showOffers(launchMode, route: route, campaignID: campaignID)
|
91
|
+
resolve(nil)
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
@objc(changeLanguage:resolver:rejecter:)
|
96
|
+
func changeLanguage(_ lang: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
97
|
+
Task {
|
98
|
+
await Tyrads.instance.changeLanguage(lang)
|
99
|
+
resolve(nil)
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
@objc
|
104
|
+
func isPrivacyAccepted(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
105
|
+
let accepted = Tyrads.instance.isPrivacyAccepted()
|
106
|
+
resolve(accepted)
|
107
|
+
}
|
108
|
+
|
109
|
+
@objc
|
110
|
+
func checkOnboardingProcess(_ resolver: @escaping RCTPromiseResolveBlock,rejecter: @escaping RCTPromiseRejectBlock) {
|
111
|
+
Task {
|
112
|
+
let result = await Tyrads.instance.checkOnboardingProcess()
|
113
|
+
resolver(result)
|
114
|
+
}
|
115
|
+
}
|
61
116
|
|
62
117
|
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.default = void 0;
|
7
|
+
var _reactNative = require("react-native");
|
8
|
+
const LINKING_ERROR = `The package 'tyrads-sdk' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
|
9
|
+
ios: "- You have run 'pod install'\n",
|
10
|
+
default: ''
|
11
|
+
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
12
|
+
const TyradsSdk = _reactNative.NativeModules.TyradsSdk ? _reactNative.NativeModules.TyradsSdk : new Proxy({}, {
|
13
|
+
get() {
|
14
|
+
throw new Error(LINKING_ERROR);
|
15
|
+
}
|
16
|
+
});
|
17
|
+
const TyradsNativeMethods = {
|
18
|
+
isPrivacyAccepted: async () => {
|
19
|
+
try {
|
20
|
+
return await TyradsSdk.isPrivacyAccepted();
|
21
|
+
} catch (err) {
|
22
|
+
console.error("Error checking privacy acceptance:", err);
|
23
|
+
return false;
|
24
|
+
}
|
25
|
+
},
|
26
|
+
checkOnboardingProcess: async () => {
|
27
|
+
try {
|
28
|
+
const result = await TyradsSdk.checkOnboardingProcess();
|
29
|
+
return result === true;
|
30
|
+
} catch (err) {
|
31
|
+
console.error("Error showing privacy flow:", err);
|
32
|
+
return false;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
};
|
36
|
+
var _default = exports.default = TyradsNativeMethods;
|
37
|
+
//# sourceMappingURL=native_methods.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","TyradsSdk","NativeModules","Proxy","get","Error","TyradsNativeMethods","isPrivacyAccepted","err","console","error","checkOnboardingProcess","result","_default","exports"],"sourceRoot":"../../../../../src","sources":["acmo/core/helpers/native_methods.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GACjB,qEAAqE,GACrEC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGC,0BAAa,CAACD,SAAS,GACrCC,0BAAa,CAACD,SAAS,GACvB,IAAIE,KAAK,CACT,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAGH,MAAMU,mBAAmB,GAAG;EAE1BC,iBAAiB,EAAE,MAAAA,CAAA,KAAY;IAC7B,IAAI;MACF,OAAO,MAAMN,SAAS,CAACM,iBAAiB,CAAC,CAAC;IAC5C,CAAC,CAAC,OAAOC,GAAG,EAAE;MACZC,OAAO,CAACC,KAAK,CAAC,oCAAoC,EAAEF,GAAG,CAAC;MACxD,OAAO,KAAK;IACd;EACF,CAAC;EAEDG,sBAAsB,EAAE,MAAAA,CAAA,KAAY;IAClC,IAAI;MACF,MAAMC,MAAM,GAAG,MAAMX,SAAS,CAACU,sBAAsB,CAAC,CAAC;MACvD,OAAOC,MAAM,KAAK,IAAI;IACxB,CAAC,CAAC,OAAOJ,GAAG,EAAE;MACZC,OAAO,CAACC,KAAK,CAAC,6BAA6B,EAAEF,GAAG,CAAC;MACjD,OAAO,KAAK;IACd;EACF;AACF,CAAC;AAAC,IAAAK,QAAA,GAAAC,OAAA,CAAAd,OAAA,GAEaM,mBAAmB","ignoreList":[]}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.numeral = void 0;
|
7
|
+
const numeral = (value, decimals = 2) => {
|
8
|
+
const suffixes = ['', 'K', 'M', 'B', 'T'];
|
9
|
+
let suffixIndex = 0;
|
10
|
+
let dividedValue = value;
|
11
|
+
while (dividedValue >= 1000 && suffixIndex < suffixes.length - 1) {
|
12
|
+
dividedValue /= 1000;
|
13
|
+
suffixIndex++;
|
14
|
+
}
|
15
|
+
const roundedValue = Math.floor(dividedValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
|
16
|
+
return `${roundedValue}${suffixes[suffixIndex]}`;
|
17
|
+
};
|
18
|
+
exports.numeral = numeral;
|
19
|
+
//# sourceMappingURL=numeral.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"names":["numeral","value","decimals","suffixes","suffixIndex","dividedValue","length","roundedValue","Math","floor","pow","exports"],"sourceRoot":"../../../../../src","sources":["acmo/core/helpers/numeral.ts"],"mappings":";;;;;;AAAO,MAAMA,OAAO,GAAGA,CAACC,KAAa,EAAEC,QAAgB,GAAG,CAAC,KAAa;EACtE,MAAMC,QAAQ,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;EACzC,IAAIC,WAAW,GAAG,CAAC;EACnB,IAAIC,YAAY,GAAGJ,KAAK;EAExB,OAAOI,YAAY,IAAI,IAAI,IAAID,WAAW,GAAGD,QAAQ,CAACG,MAAM,GAAG,CAAC,EAAE;IAChED,YAAY,IAAI,IAAI;IACpBD,WAAW,EAAE;EACf;EAEA,MAAMG,YAAY,GAAGC,IAAI,CAACC,KAAK,CAACJ,YAAY,GAAGG,IAAI,CAACE,GAAG,CAAC,EAAE,EAAER,QAAQ,CAAC,CAAC,GAAGM,IAAI,CAACE,GAAG,CAAC,EAAE,EAAER,QAAQ,CAAC;EAE/F,OAAO,GAAGK,YAAY,GAAGJ,QAAQ,CAACC,WAAW,CAAC,EAAE;AAClD,CAAC;AAACO,OAAA,CAAAX,OAAA,GAAAA,OAAA","ignoreList":[]}
|