Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Mixin.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,7 @@
944F547F2E45F9A20064A9A2 /* WatchingAddresses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944F547E2E45F99F0064A9A2 /* WatchingAddresses.swift */; };
94509BC12DDDFC5D00DC6A43 /* RefreshWeb3TokenJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94509BC02DDDFC5800DC6A43 /* RefreshWeb3TokenJob.swift */; };
94509D772DE086E100DC6A43 /* IAPTransactionObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94509D762DE086D800DC6A43 /* IAPTransactionObserver.swift */; };
9450EB642FC8964E003534FF /* UserOperationAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9450EB632FC89647003534FF /* UserOperationAnalytics.swift */; };
94510FBB2C85673C00ACD972 /* ReloadGlobalMarketJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94510FBA2C85673C00ACD972 /* ReloadGlobalMarketJob.swift */; };
94510FCE2C8742BC00ACD972 /* MarketTokenSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94510FCD2C8742BC00ACD972 /* MarketTokenSelectorViewController.swift */; };
94510FD42C8743AA00ACD972 /* MarketTokenSelectorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94510FD22C8743AA00ACD972 /* MarketTokenSelectorCell.swift */; };
Expand Down Expand Up @@ -2891,6 +2892,7 @@
944F547E2E45F99F0064A9A2 /* WatchingAddresses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchingAddresses.swift; sourceTree = "<group>"; };
94509BC02DDDFC5800DC6A43 /* RefreshWeb3TokenJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshWeb3TokenJob.swift; sourceTree = "<group>"; };
94509D762DE086D800DC6A43 /* IAPTransactionObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAPTransactionObserver.swift; sourceTree = "<group>"; };
9450EB632FC89647003534FF /* UserOperationAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserOperationAnalytics.swift; sourceTree = "<group>"; };
94510FBA2C85673C00ACD972 /* ReloadGlobalMarketJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReloadGlobalMarketJob.swift; sourceTree = "<group>"; };
94510FCD2C8742BC00ACD972 /* MarketTokenSelectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketTokenSelectorViewController.swift; sourceTree = "<group>"; };
94510FD22C8743AA00ACD972 /* MarketTokenSelectorCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketTokenSelectorCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6636,6 +6638,7 @@
948CFAE92F2CB4B200BC34C3 /* QRCodeDetector.swift */,
94EC9CD32F2C7CC000B3CD82 /* VideoCaptureDevice.swift */,
9404D76F2FB1A72600F5563A /* SignPosition.swift */,
9450EB632FC89647003534FF /* UserOperationAnalytics.swift */,
);
path = Service;
sourceTree = "<group>";
Expand Down Expand Up @@ -8523,6 +8526,7 @@
7B2AFEE220FE022C00C747BB /* MXMFastURLDetector.m in Sources */,
DF1F277C21A53585009A74C6 /* BackupViewController.swift in Sources */,
942FD9342D3A70DB004DCC4C /* TradeOrderHeaderCell.swift in Sources */,
9450EB642FC8964E003534FF /* UserOperationAnalytics.swift in Sources */,
945FFC7A2C3818630013DC51 /* RouteAPI.swift in Sources */,
ABCB87DD23F18A3D00780E60 /* PermissionsViewController.swift in Sources */,
9443A9212CA6BB3D0030A636 /* MarketAlertCoinPickerViewController.swift in Sources */,
Expand Down
32 changes: 32 additions & 0 deletions Mixin/Service/UserOperationAnalytics.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation

enum UserOperationAnalytics {

enum TradeSource: String {
case walletHome = "wallet_home"
case moreExplore = "more_explore"
case appCard = "app_card"
case marketDetail = "market_detail"
case tradeDetail = "trade_detail"
case assetDetail = "asset_detail"
case perpsMarginInput = "perps_margin_input"
case transfer = "transfer"
case withdraw = "withdraw"
case scheme = "scheme"
}

static var tradeSource: TradeSource?

}

extension UserOperationAnalytics {

enum AddMobileNumberSource: String {
case recoveryKitGuide = "recovery_kit_guide"
case buyGuide = "buy_guide"
case settings = "settings"
}

static var addMobileNumberSource: AddMobileNumberSource?

}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ final class ExploreViewController: UIViewController, AssetChangeAccountRecoveryC
reporter.report(event: .buyStart, tags: ["wallet": "main", "source": "explore"])
case .trade:
BadgeManager.shared.setHasViewed(identifier: .trade)
UserOperationAnalytics.tradeSource = .moreExplore
let trade = TradeViewController(
wallet: .privacy,
trading: nil,
Expand All @@ -137,7 +138,6 @@ final class ExploreViewController: UIViewController, AssetChangeAccountRecoveryC
}
withAccountRecoveryChecked { [weak self] in
self?.navigationController?.pushViewController(trade, animated: true)
reporter.report(event: .tradeStart, tags: ["wallet": "main", "source": "explore"])
}
case .membership:
if let membership = LoginManager.shared.account?.membership, let plan = membership.plan {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ final class CreateAccountIntroductionViewController: UIViewController {
@IBOutlet weak var continueButton: UIButton!
@IBOutlet weak var footerTextView: IntroTextView!

private let analyticSource: String

init(analyticSource: String) {
self.analyticSource = analyticSource
let nib = R.nib.createAccountIntroductionView
super.init(nibName: nib.name, bundle: nib.bundle)
}

required init?(coder: NSCoder) {
fatalError("Storyboard not supported")
}

override func viewDidLoad() {
super.viewDidLoad()
titleLabel.text = R.string.localizable.create_your_account()
Expand Down Expand Up @@ -56,7 +68,7 @@ final class CreateAccountIntroductionViewController: UIViewController {
guard let navigationController else {
return
}
presentingViewController.dismiss(animated: true) {
presentingViewController.dismiss(animated: true) { [analyticSource] in
let mnemonics: MixinMnemonics? = if let entropy = AppGroupKeychain.mnemonics {
try? MixinMnemonics(entropy: entropy)
} else {
Expand All @@ -69,7 +81,7 @@ final class CreateAccountIntroductionViewController: UIViewController {
viewControllers.append(next)
navigationController.setViewControllers(viewControllers, animated: true)
Logger.login.info(category: "CreateAccountIntro", message: "Sign up start")
reporter.report(event: .signUpStart)
reporter.report(event: .signUpStart, tags: ["source": analyticSource])
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ final class OnboardingViewController: UIViewController {
}

@IBAction func signUp(_ sender: Any) {
let intro = CreateAccountIntroductionViewController()
let intro = CreateAccountIntroductionViewController(analyticSource: "landing")
present(intro, animated: true)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ final class SignInWithMnemonicsViewController: InputMnemonicsViewController {

override func confirm(_ sender: Any) {
if phrasesCount == nil {
let intro = CreateAccountIntroductionViewController()
let intro = CreateAccountIntroductionViewController(
analyticSource: "login_mnemonic_phrase"
)
present(intro, animated: true)
} else {
do {
Expand Down Expand Up @@ -188,6 +190,11 @@ final class SignInWithMnemonicsViewController: InputMnemonicsViewController {
return
}
input(phrases: phrases)
let bottomOffset = CGPoint(
x: scrollView.contentOffset.x,
y: max(0, scrollView.contentSize.height - scrollView.frame.height)
)
scrollView.setContentOffset(bottomOffset, animated: true)
}

@objc private func emptyPhrases(_ sender: Any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ final class SignInWithMobileNumberViewController: MobileNumberViewController {
}

@objc private func signup(_ sender: Any) {
let intro = CreateAccountIntroductionViewController()
let intro = CreateAccountIntroductionViewController(analyticSource: "login_start")
present(intro, animated: true)
}

Expand Down Expand Up @@ -153,7 +153,16 @@ extension SignInWithMobileNumberViewController {
fallthrough
}
default:
reporter.report(event: .errorSessionVerifications, tags: ["source": "sign_up"])
var tags = ["type": "phone"]
if error.isServerErrorResponse {
tags["error_type"] = "server_error"
} else if error.isClientErrorResponse {
tags["error_type"] = "client_error"
}
if let statusCode = self.request?.response?.statusCode {
tags["error_code"] = "\(statusCode)"
}
reporter.report(event: .errorSessionVerifications, tags: tags)
var userInfo: [String: String] = [:]
userInfo["error"] = "\(error)"
if let requestId = self.request?.response?.value(forHTTPHeaderField: "x-request-id") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extension AddMobileNumberViewController: UITableViewDelegate {

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
UserOperationAnalytics.addMobileNumberSource = .settings
let introduction = MobileNumberIntroductionViewController(action: .add)
navigationController?.pushViewController(introduction, animated: true)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import UIKit
import MixinServices

final class MobileNumberIntroductionViewController: IntroductionViewController {

Expand Down Expand Up @@ -44,6 +45,12 @@ final class MobileNumberIntroductionViewController: IntroductionViewController {
actionButton.setTitle(R.string.localizable.continue(), for: .normal)
actionButton.titleLabel?.setFont(scaledFor: .systemFont(ofSize: 16, weight: .medium), adjustForContentSize: true)
actionButton.addTarget(self, action: #selector(continueToNext(_:)), for: .touchUpInside)

if let source = UserOperationAnalytics.tradeSource?.rawValue {
reporter.report(event: .addPhoneStart, tags: ["source": source])
} else {
reporter.report(event: .addPhoneStart)
}
}

@objc private func continueToNext(_ sender: Any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,23 @@ class VerifyMobileNumberOneTimeCodeViewController: VerificationCodeViewControlle
case .success(let account):
LoginManager.shared.setAccount(account)
self.verificationCodeField.resignFirstResponder()
let alert = switch self.context.intent {
let alert: UIAlertController
switch self.context.intent {
case .periodicVerification:
UIAlertController(
alert = UIAlertController(
title: R.string.localizable.verification_successful(),
message: R.string.localizable.sms_verified_description(),
preferredStyle: .alert
)
case .addMobileNumber:
UIAlertController(
alert = UIAlertController(
title: R.string.localizable.mobile_number_added(),
message: R.string.localizable.mobile_number_added_description(),
preferredStyle: .alert
)
reporter.report(event: .addPhoneEnd)
case .changeMobileNumber:
UIAlertController(
alert = UIAlertController(
title: R.string.localizable.mobile_number_changed(),
message: R.string.localizable.sms_verified_description(),
preferredStyle: .alert
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,17 @@ extension RecoveryKitViewController: UITableViewDelegate {
let next: UIViewController
switch indexPath.row {
case 0:
next = if let number = account.phone, !account.isAnonymous {
ChangeMobileNumberViewController(phoneNumber: number)
if let number = account.phone, !account.isAnonymous {
next = ChangeMobileNumberViewController(phoneNumber: number)
} else {
AddMobileNumberViewController()
UserOperationAnalytics.addMobileNumberSource = .recoveryKitGuide
next = AddMobileNumberViewController()
}
case 1:
next = ExportMnemonicPhrasesViewController()
default:
if account.isAnonymous {
UserOperationAnalytics.addMobileNumberSource = .recoveryKitGuide
let tip = PopupTipViewController(tip: .addMobileNumber(.setRecoveryContact))
present(tip, animated: true)
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extension Account {
onVerificationNeeded: (PopupTipViewController) -> Void,
) {
if isAnonymous {
UserOperationAnalytics.addMobileNumberSource = .buyGuide
let tip = PopupTipViewController(tip: .addMobileNumber(.buyToken))
onVerificationNeeded(tip)
} else if isPhoneVerificationValid {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ extension CommonWalletViewController: WalletHeaderView.Delegate {
self?.present(selector, animated: true, completion: nil)
}
case .trade:
UserOperationAnalytics.tradeSource = .walletHome
let trade = TradeViewController(
wallet: .common(wallet),
supportedChainIDs: supportedChainIDs,
Expand All @@ -477,14 +478,7 @@ extension CommonWalletViewController: WalletHeaderView.Delegate {
return
}
withAccountRecoveryChecked { [weak self] in
guard let self else {
return
}
self.navigationController?.pushViewController(trade, animated: true)
reporter.report(
event: .tradeStart,
tags: ["wallet": "web3", "source": "wallet_home"]
)
self?.navigationController?.pushViewController(trade, animated: true)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ extension MarketViewController: PillActionView.Delegate {
alert(R.string.localizable.swap_not_supported(market.symbol))
} else {
pickSingleToken { token in
UserOperationAnalytics.tradeSource = .marketDetail
let trade = TradeViewController(
wallet: .privacy,
trading: nil,
Expand All @@ -671,10 +672,6 @@ extension MarketViewController: PillActionView.Delegate {
)
if let trade {
self.navigationController?.pushViewController(trade, animated: true)
reporter.report(
event: .tradeStart,
tags: ["wallet": "main", "source": "market_detail"]
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ extension MixinTokenViewController: TokenActionView.Delegate {
self?.send()
}
case .trade:
UserOperationAnalytics.tradeSource = .assetDetail
let trade = TradeViewController(
wallet: .privacy,
trading: nil,
Expand All @@ -203,14 +204,7 @@ extension MixinTokenViewController: TokenActionView.Delegate {
return
}
withAccountRecoveryChecked { [weak self] in
guard let self else {
return
}
self.navigationController?.pushViewController(trade, animated: true)
reporter.report(
event: .tradeStart,
tags: ["wallet": "main", "source": "asset_detail"]
)
self?.navigationController?.pushViewController(trade, animated: true)
}
case .buy:
break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,16 @@ final class OpenPerpetualPositionPreviewViewController: WalletIdentifyingAuthent
reloadData(with: rows)
}

override func confirm(_ sender: Any) {
super.confirm(sender)
reporter.report(event: .tradePerpsPreviewConfirm)
}

override func close(_ sender: Any) {
super.close(sender)
reporter.report(event: .tradePerpsPreviewCancel)
}

override func performAction(with pin: String) {
canDismissInteractively = false
tableHeaderView.setIcon(progress: .busy)
Expand Down Expand Up @@ -226,6 +236,13 @@ final class OpenPerpetualPositionPreviewViewController: WalletIdentifyingAuthent
if let callback = context.onDismissAfterSuccess {
onDismiss = callback
}
reporter.report(
event: .tradePerpsOpenPositionEnd,
tags: [
"leverage": "\(context.leverageMultiplier)",
"trade_asset_level": operation.amount.reportingAssetLevel,
]
)
}
} catch {
let errorDescription = if let error = error as? MixinAPIError, PINVerificationFailureHandler.canHandle(error: error) {
Expand Down
Loading