mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-08-23 06:17:17 +02:00
chore: migrate to new version + fixed several critical bugs
- Migrated project to latest Telegram iOS base (v12.3.2+) - Fixed circular dependency between GhostModeManager and MiscSettingsManager - Fixed multiple Bazel build configuration errors (select() default conditions) - Fixed duplicate type definitions in PeerInfoScreen - Fixed swiftmodule directory resolution in build scripts - Added Ghostgram Settings tab in main Settings menu with all 5 features - Cleared sensitive credentials from config.json (template-only now) - Excluded bazel-cache from version control
This commit is contained in:
@@ -42,6 +42,8 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Stars/BalanceNeededScreen",
|
||||
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
|
||||
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
|
||||
"//submodules/TelegramUI/Components/AlertComponent",
|
||||
"//submodules/TelegramUI/Components/AlertComponent/AlertInputFieldComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
+108
-73
@@ -6,106 +6,141 @@ import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import PasswordSetupUI
|
||||
import Markdown
|
||||
import OwnershipTransferController
|
||||
import ComponentFlow
|
||||
import AlertComponent
|
||||
import AlertInputFieldComponent
|
||||
|
||||
public func confirmStarsRevenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, amount: Int64, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
|
||||
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let strings = presentationData.strings
|
||||
|
||||
let inputState = AlertInputFieldComponent.ExternalState()
|
||||
|
||||
let doneIsEnabled: Signal<Bool, NoError> = inputState.valueSignal
|
||||
|> map { value in
|
||||
return !value.isEmpty
|
||||
}
|
||||
|
||||
let doneInProgressPromise = ValuePromise<Bool>(false)
|
||||
|
||||
var content: [AnyComponentWithIdentity<AlertComponentEnvironment>] = []
|
||||
content.append(AnyComponentWithIdentity(
|
||||
id: "title",
|
||||
component: AnyComponent(
|
||||
AlertTitleComponent(title: strings.Monetization_Withdraw_EnterPassword_Title)
|
||||
)
|
||||
))
|
||||
content.append(AnyComponentWithIdentity(
|
||||
id: "text",
|
||||
component: AnyComponent(
|
||||
AlertTextComponent(content: .plain(strings.Monetization_Withdraw_EnterPassword_Text))
|
||||
)
|
||||
))
|
||||
|
||||
var applyImpl: (() -> Void)?
|
||||
content.append(AnyComponentWithIdentity(
|
||||
id: "input",
|
||||
component: AnyComponent(
|
||||
AlertInputFieldComponent(
|
||||
context: context,
|
||||
placeholder: strings.Channel_OwnershipTransfer_PasswordPlaceholder,
|
||||
isSecureTextEntry: true,
|
||||
isInitiallyFocused: true,
|
||||
externalState: inputState,
|
||||
returnKeyAction: {
|
||||
applyImpl?()
|
||||
}
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
var effectiveUpdatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)
|
||||
if let updatedPresentationData {
|
||||
effectiveUpdatedPresentationData = updatedPresentationData
|
||||
} else {
|
||||
effectiveUpdatedPresentationData = (presentationData, context.sharedContext.presentationData)
|
||||
}
|
||||
|
||||
var dismissImpl: (() -> Void)?
|
||||
var proceedImpl: (() -> Void)?
|
||||
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
let contentNode = ChannelOwnershipTransferAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, title: presentationData.strings.Monetization_Withdraw_EnterPassword_Title, text: presentationData.strings.Monetization_Withdraw_EnterPassword_Text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?()
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Monetization_Withdraw_EnterPassword_Done, action: {
|
||||
proceedImpl?()
|
||||
})])
|
||||
|
||||
contentNode.complete = {
|
||||
proceedImpl?()
|
||||
}
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||
let presentationDataDisposable = (updatedPresentationData?.signal ?? context.sharedContext.presentationData).start(next: { [weak controller, weak contentNode] presentationData in
|
||||
controller?.theme = AlertControllerTheme(presentationData: presentationData)
|
||||
contentNode?.theme = presentationData.theme
|
||||
})
|
||||
controller.dismissed = { _ in
|
||||
presentationDataDisposable.dispose()
|
||||
disposable.dispose()
|
||||
}
|
||||
dismissImpl = { [weak controller, weak contentNode] in
|
||||
contentNode?.dismissInput()
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
proceedImpl = { [weak contentNode] in
|
||||
guard let contentNode = contentNode else {
|
||||
return
|
||||
}
|
||||
contentNode.updateIsChecking(true)
|
||||
|
||||
let signal = context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, ton: false, amount: amount, password: contentNode.password)
|
||||
disposable.set((signal |> deliverOnMainQueue).start(next: { url in
|
||||
let alertController = AlertScreen(
|
||||
configuration: AlertScreen.Configuration(allowInputInset: true),
|
||||
content: content,
|
||||
actions: [
|
||||
.init(title: strings.Common_Cancel),
|
||||
.init(title: strings.Monetization_Withdraw_EnterPassword_Done, type: .default, action: {
|
||||
applyImpl?()
|
||||
}, autoDismiss: false, isEnabled: doneIsEnabled, progress: doneInProgressPromise.get())
|
||||
],
|
||||
updatedPresentationData: effectiveUpdatedPresentationData
|
||||
)
|
||||
applyImpl = {
|
||||
doneInProgressPromise.set(true)
|
||||
|
||||
let _ = (context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, ton: false, amount: amount, password: inputState.value)
|
||||
|> deliverOnMainQueue).start(next: { url in
|
||||
dismissImpl?()
|
||||
completion(url)
|
||||
}, error: { [weak contentNode] error in
|
||||
}, error: { error in
|
||||
var errorTextAndActions: (String, [TextAlertAction])?
|
||||
switch error {
|
||||
case .invalidPassword:
|
||||
contentNode?.animateError()
|
||||
case .limitExceeded:
|
||||
errorTextAndActions = (presentationData.strings.TwoStepAuth_FloodError, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
default:
|
||||
errorTextAndActions = (presentationData.strings.Login_UnknownError, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
case .invalidPassword:
|
||||
inputState.animateError()
|
||||
case .limitExceeded:
|
||||
errorTextAndActions = (strings.TwoStepAuth_FloodError, [TextAlertAction(type: .defaultAction, title: strings.Common_OK, action: {})])
|
||||
default:
|
||||
errorTextAndActions = (strings.Login_UnknownError, [TextAlertAction(type: .defaultAction, title: strings.Common_OK, action: {})])
|
||||
}
|
||||
contentNode?.updateIsChecking(false)
|
||||
|
||||
doneInProgressPromise.set(false)
|
||||
|
||||
if let (text, actions) = errorTextAndActions {
|
||||
dismissImpl?()
|
||||
present(textAlertController(context: context, title: nil, text: text, actions: actions), nil)
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
return controller
|
||||
dismissImpl = { [weak alertController] in
|
||||
alertController?.dismiss(completion: nil)
|
||||
}
|
||||
return alertController
|
||||
}
|
||||
|
||||
public func starsRevenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, amount: Int64, initialError: RequestStarsRevenueWithdrawalError, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
|
||||
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
let theme = AlertControllerTheme(presentationData: presentationData)
|
||||
let strings = presentationData.strings
|
||||
|
||||
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
var text = presentationData.strings.Monetization_Withdraw_SecurityRequirements
|
||||
let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0
|
||||
|
||||
var actions: [TextAlertAction] = []
|
||||
var title: String? = strings.OwnershipTransfer_SecurityCheck
|
||||
var text = strings.Monetization_Withdraw_SecurityRequirements
|
||||
|
||||
var actions: [AlertScreen.Action] = [
|
||||
.init(title: strings.Common_OK, type: .default)
|
||||
]
|
||||
switch initialError {
|
||||
case .requestPassword:
|
||||
case .requestPassword:
|
||||
return confirmStarsRevenueWithdrawalController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, amount: amount, present: present, completion: completion)
|
||||
case .twoStepAuthTooFresh, .authSessionTooFresh:
|
||||
text = text + presentationData.strings.Monetization_Withdraw_ComeBackLater
|
||||
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
|
||||
case .twoStepAuthMissing:
|
||||
actions = [TextAlertAction(type: .genericAction, title: presentationData.strings.OwnershipTransfer_SetupTwoStepAuth, action: {
|
||||
case .twoStepAuthTooFresh, .authSessionTooFresh:
|
||||
text = text + strings.Monetization_Withdraw_ComeBackLater
|
||||
case .twoStepAuthMissing:
|
||||
actions = [
|
||||
.init(title: strings.OwnershipTransfer_SetupTwoStepAuth, type: .default, action: {
|
||||
let controller = SetupTwoStepVerificationController(context: context, initialState: .automatic, stateUpdated: { update, shouldDismiss, controller in
|
||||
if shouldDismiss {
|
||||
controller.dismiss()
|
||||
}
|
||||
})
|
||||
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {})]
|
||||
default:
|
||||
title = nil
|
||||
text = presentationData.strings.Login_UnknownError
|
||||
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
|
||||
}),
|
||||
.init(title: strings.Common_Cancel)
|
||||
]
|
||||
default:
|
||||
title = nil
|
||||
text = strings.Login_UnknownError
|
||||
}
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor)
|
||||
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
|
||||
|
||||
return richTextAlertController(context: context, title: title, text: attributedText, actions: actions)
|
||||
return AlertScreen(
|
||||
context: context,
|
||||
configuration: AlertScreen.Configuration(actionAlignment: .vertical),
|
||||
title: title,
|
||||
text: text,
|
||||
actions: actions
|
||||
)
|
||||
}
|
||||
|
||||
+51
-8
@@ -95,7 +95,7 @@ private final class SheetContent: CombinedComponent {
|
||||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
@@ -167,7 +167,11 @@ private final class SheetContent: CombinedComponent {
|
||||
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxStarsAmount, nanos: 0)
|
||||
case .ton:
|
||||
amountTitle = environment.strings.Stars_SellGift_TonAmountTitle
|
||||
#if DEBUG
|
||||
minAmount = StarsAmount(value: 48000000000, nanos: 0)
|
||||
#else
|
||||
minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinTonAmount, nanos: 0)
|
||||
#endif
|
||||
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxTonAmount, nanos: 0)
|
||||
}
|
||||
case let .paidMessages(_, minAmountValue, _, _, _):
|
||||
@@ -618,7 +622,14 @@ private final class SheetContent: CombinedComponent {
|
||||
}
|
||||
if state.currency == .stars {
|
||||
if let amount = state.amount, let tonUsdRate = withdrawConfiguration.tonUsdRate, let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate {
|
||||
state.amount = StarsAmount(value: max(min(convertStarsToTon(amount, tonUsdRate: tonUsdRate, starsUsdRate: usdWithdrawRate), resaleConfiguration.starGiftResaleMaxTonAmount), resaleConfiguration.starGiftResaleMinTonAmount), nanos: 0)
|
||||
var convertedValue = min(convertStarsToTon(amount, tonUsdRate: tonUsdRate, starsUsdRate: usdWithdrawRate), resaleConfiguration.starGiftResaleMaxTonAmount)
|
||||
if convertedValue < resaleConfiguration.starGiftResaleMinTonAmount {
|
||||
convertedValue = resaleConfiguration.starGiftResaleMinTonAmount
|
||||
if case .starGiftResell = component.mode, let controller = controller() as? StarsWithdrawScreen {
|
||||
controller.presentMinAmountTooltip(convertedValue, currency: .ton)
|
||||
}
|
||||
}
|
||||
state.amount = StarsAmount(value: convertedValue, nanos: 0)
|
||||
} else {
|
||||
state.amount = StarsAmount(value: 0, nanos: 0)
|
||||
}
|
||||
@@ -1255,6 +1266,8 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
|
||||
let sheet = Child(SheetComponent<(EnvironmentType)>.self)
|
||||
let animateOut = StoredActionSlot(Action<Void>.self)
|
||||
|
||||
let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[EnvironmentType.self]
|
||||
|
||||
@@ -1281,6 +1294,7 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
|
||||
followContentSizeChanges: false,
|
||||
clipsContent: true,
|
||||
isScrollEnabled: false,
|
||||
externalState: sheetExternalState,
|
||||
animateOut: animateOut
|
||||
),
|
||||
environment: {
|
||||
@@ -1313,6 +1327,29 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
)
|
||||
|
||||
if let controller = controller(), !controller.automaticallyControlPresentationContextLayout {
|
||||
var sideInset: CGFloat = 0.0
|
||||
var bottomInset: CGFloat = max(environment.safeInsets.bottom, sheetExternalState.contentHeight)
|
||||
if case .regular = environment.metrics.widthClass {
|
||||
sideInset = floor((context.availableSize.width - 430.0) / 2.0) - 12.0
|
||||
bottomInset = (context.availableSize.height - sheetExternalState.contentHeight) / 2.0 + sheetExternalState.contentHeight
|
||||
}
|
||||
|
||||
let layout = ContainerViewLayout(
|
||||
size: context.availableSize,
|
||||
metrics: environment.metrics,
|
||||
deviceMetrics: environment.deviceMetrics,
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomInset, right: 0.0),
|
||||
safeInsets: UIEdgeInsets(top: 0.0, left: max(sideInset, environment.safeInsets.left), bottom: 0.0, right: max(sideInset, environment.safeInsets.right)),
|
||||
additionalInsets: .zero,
|
||||
statusBarHeight: environment.statusBarHeight,
|
||||
inputHeight: nil,
|
||||
inputHeightIsInteractivellyChanging: false,
|
||||
inVoiceOver: false
|
||||
)
|
||||
controller.presentationContext.containerLayoutUpdated(layout, transition: context.transition.containedViewLayoutTransition)
|
||||
}
|
||||
|
||||
return context.availableSize
|
||||
}
|
||||
}
|
||||
@@ -1357,6 +1394,7 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
||||
)
|
||||
|
||||
self.navigationPresentation = .flatModal
|
||||
self.automaticallyControlPresentationContextLayout = false
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
@@ -1422,10 +1460,8 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
||||
round: false,
|
||||
undoText: nil
|
||||
),
|
||||
elevatedLayout: false,
|
||||
position: .top,
|
||||
action: { _ in return true})
|
||||
self.present(resultController, in: .window(.root))
|
||||
self.present(resultController, in: .current)
|
||||
|
||||
if let view = self.node.hostView.findTaggedView(tag: amountTag) as? AmountFieldComponent.View {
|
||||
view.animateError()
|
||||
@@ -1769,8 +1805,15 @@ public final class AmountFieldComponent: Component {
|
||||
guard let component = self.component, let value = component.value else {
|
||||
return
|
||||
}
|
||||
self.textField.text = "\(value)"
|
||||
self.placeholderView.view?.isHidden = self.textField.text?.isEmpty ?? false
|
||||
var text = ""
|
||||
switch component.currency {
|
||||
case .stars:
|
||||
text = "\(value)"
|
||||
case .ton:
|
||||
text = "\(formatTonAmountText(value, dateTimeFormat: PresentationDateTimeFormat(timeFormat: component.dateTimeFormat.timeFormat, dateFormat: component.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), maxDecimalPositions: nil))"
|
||||
}
|
||||
self.textField.text = text
|
||||
self.placeholderView.view?.isHidden = !(self.textField.text ?? "").isEmpty
|
||||
}
|
||||
|
||||
func update(component: AmountFieldComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
@@ -1790,7 +1833,7 @@ public final class AmountFieldComponent: Component {
|
||||
text = "\(formatTonAmountText(value, dateTimeFormat: PresentationDateTimeFormat(timeFormat: component.dateTimeFormat.timeFormat, dateFormat: component.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), maxDecimalPositions: nil))"
|
||||
}
|
||||
self.textField.text = text
|
||||
self.placeholderView.view?.isHidden = text.isEmpty
|
||||
self.placeholderView.view?.isHidden = !text.isEmpty
|
||||
} else {
|
||||
self.textField.text = ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user