Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add handle telegram support group #6107

Merged
merged 1 commit into from
Feb 13, 2025
Merged
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
28 changes: 24 additions & 4 deletions UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,10 @@
6BA8D2432D5B0D2C0093D5C2 /* MarketSectorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D2412D5B0D2C0093D5C2 /* MarketSectorViewModel.swift */; };
6BA8D2452D5B14430093D5C2 /* SectorMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D2442D5B14430093D5C2 /* SectorMarketCapFetcher.swift */; };
6BA8D2462D5B14430093D5C2 /* SectorMarketCapFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D2442D5B14430093D5C2 /* SectorMarketCapFetcher.swift */; };
6BA8D24C2D5CA7DC0093D5C2 /* SupportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D24B2D5CA7DC0093D5C2 /* SupportViewModel.swift */; };
6BA8D24D2D5CA7DC0093D5C2 /* SupportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D24B2D5CA7DC0093D5C2 /* SupportViewModel.swift */; };
6BA8D24F2D5CA7E80093D5C2 /* SupportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D24E2D5CA7E80093D5C2 /* SupportView.swift */; };
6BA8D2502D5CA7E80093D5C2 /* SupportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA8D24E2D5CA7E80093D5C2 /* SupportView.swift */; };
6BAAF3472B9B245C00EFE5B2 /* ShimmerEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BAAF3442B9B245C00EFE5B2 /* ShimmerEffect.swift */; };
6BAAF3492B9B245C00EFE5B2 /* SlideButtonStyling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BAAF3452B9B245C00EFE5B2 /* SlideButtonStyling.swift */; };
6BAAF34B2B9B245C00EFE5B2 /* SlideButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BAAF3462B9B245C00EFE5B2 /* SlideButton.swift */; };
Expand Down Expand Up @@ -4175,6 +4179,8 @@
6BA8D23E2D5B0D1B0093D5C2 /* MarketSectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketSectorView.swift; sourceTree = "<group>"; };
6BA8D2412D5B0D2C0093D5C2 /* MarketSectorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketSectorViewModel.swift; sourceTree = "<group>"; };
6BA8D2442D5B14430093D5C2 /* SectorMarketCapFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorMarketCapFetcher.swift; sourceTree = "<group>"; };
6BA8D24B2D5CA7DC0093D5C2 /* SupportViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportViewModel.swift; sourceTree = "<group>"; };
6BA8D24E2D5CA7E80093D5C2 /* SupportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportView.swift; sourceTree = "<group>"; };
6BAAF3442B9B245C00EFE5B2 /* ShimmerEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShimmerEffect.swift; sourceTree = "<group>"; };
6BAAF3452B9B245C00EFE5B2 /* SlideButtonStyling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlideButtonStyling.swift; sourceTree = "<group>"; };
6BAAF3462B9B245C00EFE5B2 /* SlideButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlideButton.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6162,13 +6168,14 @@
11B358D87B2EDEB8BE8F133B /* Settings */ = {
isa = PBXGroup;
children = (
11B3563CCEF5817CCA5A0C6A /* Appearance */,
1A564533BEABADF4DC5F8A25 /* Main */,
1A56463750A2B2C557B399E7 /* Security */,
11B35E1B51E123DEB9F71E96 /* Terms */,
11B3586A7D20121BC532047E /* Unlink */,
11B35F2DD8307A98F05D5475 /* About */,
11B35CF31CBB2FF04B2A75AA /* BaseCurrency */,
11B3563CCEF5817CCA5A0C6A /* Appearance */,
6BA8D2472D5CA7410093D5C2 /* Support */,
1A5648A0CFE0BED4703D9794 /* Privacy */,
11B35C3CD4FFDE56E8E30B80 /* BlockchainSettings */,
D06F756D2A8BA33000184227 /* Donate */,
Expand Down Expand Up @@ -7447,6 +7454,15 @@
path = Sector;
sourceTree = "<group>";
};
6BA8D2472D5CA7410093D5C2 /* Support */ = {
isa = PBXGroup;
children = (
6BA8D24B2D5CA7DC0093D5C2 /* SupportViewModel.swift */,
6BA8D24E2D5CA7E80093D5C2 /* SupportView.swift */,
);
path = Support;
sourceTree = "<group>";
};
6BB14F782C05FAA600E879B2 /* Tvl */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -9648,6 +9664,7 @@
11B351E31777084419C3B2C0 /* CreateAccountModule.swift in Sources */,
11B3520EE4A357BCFDE52BAA /* CreateAccountAdvancedViewController.swift in Sources */,
11B3533F0C232F72DB641666 /* CreateAccountService.swift in Sources */,
6BA8D24D2D5CA7DC0093D5C2 /* SupportViewModel.swift in Sources */,
11B3598CCF5AB4D78AD4D32B /* RestoreMnemonicViewModel.swift in Sources */,
11B35F890BE41B1BFAC3D75E /* RestoreMnemonicService.swift in Sources */,
11B355836B4CFF24359C4B83 /* RestoreSelectModule.swift in Sources */,
Expand Down Expand Up @@ -9854,6 +9871,7 @@
D36DE0AC272FD612000BC916 /* SwapViewController.swift in Sources */,
D087627729815DAE00E6FFD4 /* ChooseWatchViewModel.swift in Sources */,
11B35FBC1AFDCF0DB8362C88 /* CoinAnalyticsModule.swift in Sources */,
6BA8D2502D5CA7E80093D5C2 /* SupportView.swift in Sources */,
D0118E4C2B7CC63300D55CE6 /* ResendBitcoinViewController.swift in Sources */,
D05C8E8A2D22931A006EE778 /* ChainalysisAddressValidator.swift in Sources */,
D389BC4D2C0DDCF500724504 /* MarketAdvancedSearchBlockchainsView.swift in Sources */,
Expand Down Expand Up @@ -11134,6 +11152,7 @@
11B35DA1A83CE7E402309FE7 /* CreateAccountModule.swift in Sources */,
11B35B7ABF2BE45FAE0461A5 /* CreateAccountAdvancedViewController.swift in Sources */,
11B355DB012D5856C675FE72 /* CreateAccountService.swift in Sources */,
6BA8D24C2D5CA7DC0093D5C2 /* SupportViewModel.swift in Sources */,
11B353AD1FE351B86CA538EA /* RestoreMnemonicViewModel.swift in Sources */,
11B35631E5455A54854A2A6F /* RestoreMnemonicService.swift in Sources */,
11B357F4C63379217B25AA75 /* RestoreSelectModule.swift in Sources */,
Expand Down Expand Up @@ -11340,6 +11359,7 @@
58AAA72230207B253E2153EA /* SelectorButton.swift in Sources */,
D36DE0E4272FD887000BC916 /* OneInchService.swift in Sources */,
D05E969A2A26278D002CCD71 /* TronApproveTransactionRecord.swift in Sources */,
6BA8D24F2D5CA7E80093D5C2 /* SupportView.swift in Sources */,
D05E969D2A2627AF002CCD71 /* TronContractCallTransactionRecord.swift in Sources */,
D05C8E8B2D22931A006EE778 /* ChainalysisAddressValidator.swift in Sources */,
D36DE0C9272FD864000BC916 /* UniswapProvider.swift in Sources */,
Expand Down Expand Up @@ -12519,7 +12539,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = UnstoppableWallet/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -12591,7 +12611,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = UnstoppableWallet/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -13208,7 +13228,7 @@
repositoryURL = "https://github.com/horizontalsystems/MarketKit.Swift";
requirement = {
kind = exactVersion;
version = 3.1.1;
version = 3.2.0;
};
};
D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,19 @@ class PurchaseManager: NSObject {
activeFeatures = !purchasedProducts.isEmpty ? PremiumFeature.allCases : []
}

private var getReceipt: String? {
guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
let receiptData = try? Data(contentsOf: appStoreReceiptURL)
else {
func getJws() async -> String? {
guard let purchase = activePurchase else {
return nil
}
return receiptData.base64EncodedString()

let result = await Transaction.currentEntitlements.first(where: {
switch $0 {
case let .verified(transaction): return transaction.productID == purchase.id
default: return false
}
})

return result?.jwsRepresentation
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ struct PurchaseBottomSheetView: View {
@StateObject private var viewModel: PurchaseBottomSheetViewModel

@Binding private var isPresented: Bool
@State private var redeemSheetPresented = false

init(isPresented: Binding<Bool>, onSubscribe: @escaping (PurchaseManager.ProductData) -> Void) {
_viewModel = StateObject(wrappedValue: PurchaseBottomSheetViewModel(onSubscribe: onSubscribe))
Expand All @@ -16,7 +17,7 @@ struct PurchaseBottomSheetView: View {
VStack(spacing: 0) {
HStack(spacing: .margin16) {
Image("circle_clock_24").themeIcon(color: .themeJacob)
Text("purchase.period.title").themeHeadline2()
Text("purchase.period.title".localized).themeHeadline2()

Button(action: {
isPresented = false
Expand Down Expand Up @@ -57,7 +58,7 @@ struct PurchaseBottomSheetView: View {
.buttonStyle(PrimaryButtonStyle(style: .yellowGradient))

Button(action: {
print("ABC")
redeemSheetPresented = true
}) {
Text("purchases.period.button.promo".localized)
}
Expand All @@ -66,6 +67,9 @@ struct PurchaseBottomSheetView: View {
}
.padding(EdgeInsets(top: .margin24, leading: .margin24, bottom: .margin12, trailing: .margin24))
}
.offerCodeRedemption(isPresented: $redeemSheetPresented) { result in
viewModel.handleRedeemCode(result: result)
}
}

var subscriptionState: SubscriptionState {
Expand Down Expand Up @@ -95,10 +99,8 @@ struct PurchaseBottomSheetView: View {
Text("purchase.lifetime.description").foregroundColor(.themeGray).font(.themeSubhead2)

case .freeTrial:

Text("purchase.period.description1".localized + " ").foregroundColor(.themeRemus).font(.themeSubhead2) +
Text("purchase.period.description2".localized).foregroundColor(.themeGray).font(.themeSubhead2)

case .subscribe:
Text("purchase.period.description2".localized).foregroundColor(.themeGray).font(.themeSubhead2)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Foundation

class PurchaseBottomSheetViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
private var waitTask: Task<Void, Never>?

@Published var items: [Item] = []
@Published var selectedItem: Item?
Expand All @@ -27,8 +28,7 @@ class PurchaseBottomSheetViewModel: ObservableObject {

purchaseManager.$purchaseData
.receive(on: DispatchQueue.main)
.sink { [weak self] purchases in
self?.allowTrialPeriod = !purchases.isEmpty
.sink { [weak self] in self?.handle(purchases: $0)
}
.store(in: &cancellables)

Expand All @@ -55,23 +55,52 @@ class PurchaseBottomSheetViewModel: ObservableObject {
}
}

private func waitTransaction() {
waitTask?.cancel()

waitTask = Task { [weak self] in
await self?.update(state: .loading)

do {
try await Task.sleep(nanoseconds: 5_000_000_000)

if !Task.isCancelled {
await self?.update(state: .idle)
}
} catch {
await self?.update(state: .idle)
}
}
}

private func handle(purchases: [PurchaseManager.PurchaseData]) {
allowTrialPeriod = !purchases.isEmpty

if let purchase = purchaseManager.activePurchase, let product = purchaseManager.productData.first(where: { $0.id == purchase.id }) {
waitTask?.cancel()
waitTask = nil

onSubscribe(product)
}
}

func subscribe() {
Task {
await update(state: .loading)
Task { [weak self] in
await self?.update(state: .loading)

do {
guard let selectedItem else {
guard let selectedItem = self?.selectedItem else {
return
}

try await purchaseManager.purchase(product: selectedItem.product)
try await self?.purchaseManager.purchase(product: selectedItem.product)

await update(state: .idle)
await self?.update(state: .idle)

onSubscribe(selectedItem.product)
self?.onSubscribe(selectedItem.product)
} catch {
print("ERROR: \(error)") // TODO: Handle error
await update(state: .idle)
await self?.update(state: .idle)
}
}
}
Expand All @@ -81,6 +110,15 @@ extension PurchaseBottomSheetViewModel {
func set(item: Item) {
selectedItem = item
}

func handleRedeemCode(result: Result<Void, any Error>) {
switch result {
case .success(): // wait transaction and handle it
waitTransaction()
case let .failure(error): // don't doing anything
print(error)
}
}
}

extension PurchaseBottomSheetViewModel {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import StoreKit
import SwiftUI

struct PurchasesView: View {
Expand Down Expand Up @@ -43,7 +44,6 @@ struct PurchasesView: View {
}
}
.themeListStyle(.steel10WithCorners(.allCorners))
.modifier(ThemeListStyleModifier(themeListStyle: .steel10WithCorners(.allCorners), cornerRadius: .cornerRadius16))
.padding(.horizontal, .margin16)

walletDescription()
Expand Down Expand Up @@ -86,12 +86,17 @@ struct PurchasesView: View {
}
.bottomSheet(item: $presentedInfoViewItem) { viewItem in
BottomSheetView(
icon: .local(name: viewItem.iconName, tint: .themeLucian),
icon: .local(name: viewItem.iconName, tint: .themeJacob),
title: "purchases.\(viewItem.title)".localized,
titleColor: .themeJacob,
titleColor: .themeLeah,
items: [
.text(text: "purchases.\(viewItem.title).info".localized),
],
buttons: [
.init(style: .yellow, title: "button.close".localized) {
presentedInfoViewItem = nil
},
],
onDismiss: { presentedInfoViewItem = nil }
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,11 @@ class MainSettingsViewController: ThemeViewController {

switch feature {
case .vipSupport:
UrlManager.open(url: "https://t.me/\(AppConfig.appTelegramAccount)")
let viewController = SupportView { telegramUrl in
UrlManager.open(url: telegramUrl)
}.toViewController().toBottomSheet

present(viewController, animated: true)
case .vipClub:
UrlManager.open(url: "https://t.me/\(AppConfig.appTelegramAccount)")
default: ()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

import Chart
import MarketKit
import SwiftUI

struct SupportView: View {
@StateObject private var viewModel: SupportViewModel

@Environment(\.dismiss) private var dismiss

init(onReceiveGroup: @escaping (String) -> Void) {
_viewModel = StateObject(wrappedValue: SupportViewModel(onReceiveGroup: onReceiveGroup))
}

var body: some View {
VStack(spacing: 0) {
HStack(spacing: .margin16) {
Image("support_2_24").themeIcon(color: .themeJacob)
Text("purchases.vip_support").textHeadline2()

Spacer()

Button(action: {
dismiss()
}) {
Image("close_3_24")
}
}
.padding(.horizontal, .margin32)
.padding(.top, .margin24)
.padding(.bottom, .margin12)

Image("premium_support")
.padding(.vertical, .margin24)

Text("settings.vip_support.description".localized)
.multilineTextAlignment(.leading)
.padding(EdgeInsets(top: .margin12, leading: .margin32, bottom: .margin32, trailing: .margin32))

Button(action: {
viewModel.onFetchChat()
}) {
HStack(spacing: .margin8) {
if viewModel.buttonState == .loading {
ProgressView()
}
Text("settings.vip_support.start_chat".localized)
}
}
.disabled(viewModel.buttonState == .loading)
.buttonStyle(PrimaryButtonStyle(style: .yellowGradient))
.padding(EdgeInsets(top: .margin24, leading: .margin24, bottom: .margin12, trailing: .margin24))
}
.background(Color.themeLawrence)
.onReceive(viewModel.$isPresented) { newValue in
if !newValue {
dismiss()
}
}
}
}
Loading