Various fixes

This commit is contained in:
Ilya Laktyushin 2024-02-12 17:23:30 -04:00
parent 337ae154c9
commit 59c65198de
11 changed files with 128 additions and 63 deletions

View File

@ -10988,8 +10988,8 @@ Sorry for the inconvenience.";
"ChannelBoost.MaxLevelReached.Text" = "**%1$@** reached **Level %2$@**.";
"ChannelBoost.MoreBoostsNeeded.Boosted.Text" = "%@ needed to unlock new features.";
"ChannelBoost.MoreBoostsNeeded.Boosted.Level.Text" = "This channel reached **%@** and unlocked new features.";
"GroupBoost.MoreBoostsNeeded.Boosted.Level.Text" = "This group reached **%@** and unlocked new features.";
"ChannelBoost.MoreBoostsNeeded.Boosted.Level.Text" = "This channel reached **Level %@** and unlocked new features.";
"GroupBoost.MoreBoostsNeeded.Boosted.Level.Text" = "This group reached **Level %@** and unlocked new features.";
"ContactList.Context.Delete" = "Delete Contact";
"ContactList.Context.Select" = "Select";
@ -11303,6 +11303,4 @@ Sorry for the inconvenience.";
"Channel.AdminLog.MessageChangedGroupEmojiPack" = "%@ changed group emoji pack";
"Channel.AdminLog.MessageRemovedGroupEmojiPack" = "%@ removed group emoji pack";
"Group.Appearance.EmojiPackUpdated" = "Group emoji pack updated.";
"Attachment.BoostToUnlock" = "Boost to Unlock";

View File

@ -555,7 +555,7 @@ private final class CameraContext {
}
}
public func startRecording() -> Signal<CameraRecordingData, NoError> {
public func startRecording() -> Signal<CameraRecordingData, CameraRecordingError> {
guard let mainDeviceContext = self.mainDeviceContext else {
return .complete()
}
@ -829,7 +829,7 @@ public final class Camera {
}
}
public func startRecording() -> Signal<CameraRecordingData, NoError> {
public func startRecording() -> Signal<CameraRecordingData, CameraRecordingError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.queue.async {
@ -1082,3 +1082,7 @@ public struct CameraRecordingData {
public let duration: Double
public let filePath: String
}
public enum CameraRecordingError {
case audioInitializationError
}

View File

@ -83,6 +83,8 @@ final class CameraOutput: NSObject {
let colorSpace: CGColorSpace
let isVideoMessage: Bool
var hasAudio: Bool = false
let photoOutput = AVCapturePhotoOutput()
let videoOutput = AVCaptureVideoDataOutput()
let audioOutput = AVCaptureAudioDataOutput()
@ -141,9 +143,15 @@ final class CameraOutput: NSObject {
} else {
Logger.shared.log("Camera", "Can't add video output")
}
if audio, session.session.canAddOutput(self.audioOutput) {
session.session.addOutput(self.audioOutput)
self.audioOutput.setSampleBufferDelegate(self, queue: self.audioQueue)
if audio {
if session.session.canAddOutput(self.audioOutput) {
self.hasAudio = true
session.session.addOutput(self.audioOutput)
self.audioOutput.setSampleBufferDelegate(self, queue: self.audioQueue)
} else {
Logger.shared.log("Camera", "Can't add audio output")
print("error")
}
}
if photo, session.session.canAddOutput(self.photoOutput) {
if session.hasMultiCam {
@ -302,7 +310,7 @@ final class CameraOutput: NSObject {
private var currentMode: RecorderMode = .default
private var recordingCompletionPipe = ValuePipe<VideoCaptureResult>()
func startRecording(mode: RecorderMode, position: Camera.Position? = nil, orientation: AVCaptureVideoOrientation, additionalOutput: CameraOutput? = nil) -> Signal<CameraRecordingData, NoError> {
func startRecording(mode: RecorderMode, position: Camera.Position? = nil, orientation: AVCaptureVideoOrientation, additionalOutput: CameraOutput? = nil) -> Signal<CameraRecordingData, CameraRecordingError> {
guard self.videoRecorder == nil else {
return .complete()
}
@ -345,6 +353,10 @@ final class CameraOutput: NSObject {
}
let audioSettings = self.audioOutput.recommendedAudioSettingsForAssetWriter(writingTo: .mp4) ?? [:]
if self.hasAudio && audioSettings.isEmpty {
Logger.shared.log("Camera", "Audio settings are empty on recording start")
return .fail(.audioInitializationError)
}
let outputFileName = NSUUID().uuidString
let outputFilePath = NSTemporaryDirectory() + outputFileName + ".mp4"

View File

@ -402,13 +402,15 @@ private final class SheetContent: CombinedComponent {
let mode: PremiumBoostLevelsScreen.Mode
let status: ChannelBoostStatus?
let boostState: InternalBoostState.DisplayData?
let initialized: Bool
let boost: () -> Void
let copyLink: (String) -> Void
let dismiss: () -> Void
let openStats: (() -> Void)?
let openGift: (() -> Void)?
let openPeer: ((EnginePeer) -> Void)?
let updated: () -> Void
init(context: AccountContext,
theme: PresentationTheme,
@ -419,12 +421,14 @@ private final class SheetContent: CombinedComponent {
mode: PremiumBoostLevelsScreen.Mode,
status: ChannelBoostStatus?,
boostState: InternalBoostState.DisplayData?,
initialized: Bool,
boost: @escaping () -> Void,
copyLink: @escaping (String) -> Void,
dismiss: @escaping () -> Void,
openStats: (() -> Void)?,
openGift: (() -> Void)?,
openPeer: ((EnginePeer) -> Void)?
openPeer: ((EnginePeer) -> Void)?,
updated: @escaping () -> Void
) {
self.context = context
self.theme = theme
@ -435,12 +439,14 @@ private final class SheetContent: CombinedComponent {
self.mode = mode
self.status = status
self.boostState = boostState
self.initialized = initialized
self.boost = boost
self.copyLink = copyLink
self.dismiss = dismiss
self.openStats = openStats
self.openGift = openGift
self.openPeer = openPeer
self.updated = updated
}
static func ==(lhs: SheetContent, rhs: SheetContent) -> Bool {
@ -468,6 +474,9 @@ private final class SheetContent: CombinedComponent {
if lhs.boostState != rhs.boostState {
return false
}
if lhs.initialized != rhs.initialized {
return false
}
return true
}
@ -479,35 +488,33 @@ private final class SheetContent: CombinedComponent {
private(set) var memberPeer: EnginePeer?
private var disposable: Disposable?
private var memberDisposable: Disposable?
init(context: AccountContext, peerId: EnginePeer.Id, userId: EnginePeer.Id?) {
init(context: AccountContext, peerId: EnginePeer.Id, userId: EnginePeer.Id?, updated: @escaping () -> Void) {
super.init()
self.disposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).startStrict(next: { [weak self] peer in
var peerIds: [EnginePeer.Id] = [peerId]
if let userId {
peerIds.append(userId)
}
self.disposable = (context.engine.data.get(
EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
) |> deliverOnMainQueue).startStrict(next: { [weak self] peers in
guard let self else {
return
}
self.peer = peer
self.updated()
if let maybePeer = peers[peerId] {
self.peer = maybePeer
}
if let userId, let maybePeer = peers[userId] {
self.memberPeer = maybePeer
}
updated()
})
if let userId {
self.memberDisposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: userId))
|> deliverOnMainQueue).startStrict(next: { [weak self] peer in
guard let self else {
return
}
self.memberPeer = peer
self.updated()
})
}
}
deinit {
self.disposable?.dispose()
self.memberDisposable?.dispose()
}
}
@ -516,7 +523,7 @@ private final class SheetContent: CombinedComponent {
if case let .user(mode) = mode, case let .groupPeer(peerId, _) = mode {
userId = peerId
}
return State(context: self.context, peerId: self.peerId, userId: userId)
return State(context: self.context, peerId: self.peerId, userId: userId, updated: self.updated)
}
static var body: Body {
@ -636,7 +643,11 @@ private final class SheetContent: CombinedComponent {
} else {
let boostsString = strings.ChannelBoost_MoreBoostsNeeded_Boosts(Int32(remaining))
if myBoostCount > 0 {
textString = strings.ChannelBoost_MoreBoostsNeeded_Boosted_Text(boostsString).string
if remaining == 0 {
textString = isGroup ? strings.GroupBoost_MoreBoostsNeeded_Boosted_Level_Text("\(level + 1)").string : strings.ChannelBoost_MoreBoostsNeeded_Boosted_Level_Text("\(level + 1)").string
} else {
textString = strings.ChannelBoost_MoreBoostsNeeded_Boosted_Text(boostsString).string
}
} else {
textString = strings.ChannelBoost_MoreBoostsNeeded_Text(peerName, boostsString).string
}
@ -674,7 +685,7 @@ private final class SheetContent: CombinedComponent {
let boostsString = strings.ChannelBoost_MoreBoostsNeeded_Boosts(Int32(remaining))
if myBoostCount > 0 {
if remaining == 0 {
textString = isGroup ? strings.GroupBoost_MoreBoostsNeeded_Boosted_Level_Text("\(level)").string : strings.ChannelBoost_MoreBoostsNeeded_Boosted_Level_Text("\(level)").string
textString = isGroup ? strings.GroupBoost_MoreBoostsNeeded_Boosted_Level_Text("\(level + 1)").string : strings.ChannelBoost_MoreBoostsNeeded_Boosted_Level_Text("\(level + 1)").string
} else {
textString = strings.ChannelBoost_MoreBoostsNeeded_Boosted_Text(boostsString).string
}
@ -1267,6 +1278,8 @@ private final class BoostLevelsContainerComponent: CombinedComponent {
var cachedStatsImage: (UIImage, PresentationTheme)?
var cachedCloseImage: (UIImage, PresentationTheme)?
var initialized = false
private var disposable: Disposable?
private(set) var peer: EnginePeer?
@ -1279,7 +1292,6 @@ private final class BoostLevelsContainerComponent: CombinedComponent {
return
}
self.peer = peer
self.updated()
updated()
})
}
@ -1325,6 +1337,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent {
if let isGroup {
component.externalState.isGroup = isGroup
let updated = component.updated
let scroll = scroll.update(
component: ScrollComponent<Empty>(
content: AnyComponent(
@ -1338,12 +1351,17 @@ private final class BoostLevelsContainerComponent: CombinedComponent {
mode: component.mode,
status: component.status,
boostState: component.boostState,
initialized: state.initialized,
boost: component.boost,
copyLink: component.copyLink,
dismiss: component.dismiss,
openStats: component.openStats,
openGift: component.openGift,
openPeer: component.openPeer
openPeer: component.openPeer,
updated: { [weak state] in
state?.initialized = true
updated()
}
)
),
externalState: externalScrollState,
@ -1757,9 +1775,16 @@ public class PremiumBoostLevelsScreen: ViewController {
self.controller?.updateModalStyleOverlayTransitionFactor(0.0, transition: positionTransition)
}
func requestLayout(transition: Transition) {
guard let layout = self.currentLayout else {
return
}
self.containerLayoutUpdated(layout: layout, forceUpdate: true, transition: transition)
}
private var dismissOffset: CGFloat?
func containerLayoutUpdated(layout: ContainerViewLayout, transition: Transition) {
func containerLayoutUpdated(layout: ContainerViewLayout, forceUpdate: Bool = false, transition: Transition) {
guard !self.isDismissing else {
return
}
@ -1824,7 +1849,7 @@ public class PremiumBoostLevelsScreen: ViewController {
effectiveExpanded = true
}
self.updated(transition: transition)
self.updated(transition: transition, forceUpdate: forceUpdate)
let contentHeight = self.containerExternalState.contentHeight
if contentHeight > 0.0 && contentHeight < 400.0, let view = self.footerView.componentView as? FooterComponent.View {
@ -1856,7 +1881,7 @@ public class PremiumBoostLevelsScreen: ViewController {
}
private var boostState: InternalBoostState.DisplayData?
func updated(transition: Transition) {
func updated(transition: Transition, forceUpdate: Bool = false) {
guard let controller = self.controller else {
return
}
@ -1895,11 +1920,12 @@ public class PremiumBoostLevelsScreen: ViewController {
openGift: controller.openGift,
openPeer: controller.openPeer,
updated: { [weak self] in
self?.controller?.requestLayout(transition: .immediate)
self?.requestLayout(transition: .immediate)
}
)
),
environment: {},
forceUpdate: forceUpdate,
containerSize: self.containerView.bounds.size
)
self.contentView.frame = CGRect(origin: .zero, size: contentSize)
@ -2200,6 +2226,7 @@ public class PremiumBoostLevelsScreen: ViewController {
let canBoostAgain = premiumConfiguration.boostsPerGiftCount > 0
let presentationData = self.presentationData
let forceDark = controller.forceDark
let boostStatusUpdated = controller.boostStatusUpdated
if let _ = status?.nextLevelBoosts {
if let availableBoost = self.availableBoosts.first {
@ -2266,15 +2293,23 @@ public class PremiumBoostLevelsScreen: ViewController {
).startStandalone(next: { boostStatus, myBoostStatus in
dismissReplaceImpl?()
if let boostStatus {
boostStatusUpdated(boostStatus)
}
let levelsController = PremiumBoostLevelsScreen(
context: context,
peerId: peerId,
mode: mode,
status: status,
status: boostStatus,
myBoostStatus: myBoostStatus,
replacedBoosts: (Int32(slots.count), sourcePeers),
openStats: nil, openGift: nil, openPeer: openPeer, forceDark: forceDark
openStats: nil,
openGift: nil,
openPeer: openPeer,
forceDark: forceDark
)
levelsController.boostStatusUpdated = boostStatusUpdated
if let navigationController {
navigationController.pushViewController(levelsController, animated: true)
}

View File

@ -378,7 +378,7 @@ public func mediaContentKind(_ media: EngineMedia, message: EngineMessage? = nil
}
case .story:
return .story
case .giveaway:
case .giveaway, .giveawayResults:
return .giveaway
case let .webpage(webpage):
if let message, message.text.isEmpty, case let .Loaded(content) = webpage.content {

View File

@ -2184,19 +2184,21 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
let attributedString: NSAttributedString
var adminBadgeString: NSAttributedString?
var boostBadgeString: NSAttributedString?
if let authorRank = authorRank {
let string: String
switch authorRank {
if incoming {
if let authorRank = authorRank {
let string: String
switch authorRank {
case .owner:
string = item.presentationData.strings.Conversation_Owner
case .admin:
string = item.presentationData.strings.Conversation_Admin
case let .custom(rank):
string = rank.trimmingEmojis
}
adminBadgeString = NSAttributedString(string: " \(string)", font: inlineBotPrefixFont, textColor: messageTheme.secondaryTextColor)
} else if authorIsChannel, case .peer = item.chatLocation {
adminBadgeString = NSAttributedString(string: " \(item.presentationData.strings.Channel_Status)", font: inlineBotPrefixFont, textColor: messageTheme.secondaryTextColor)
}
adminBadgeString = NSAttributedString(string: " \(string)", font: inlineBotPrefixFont, textColor: messageTheme.secondaryTextColor)
} else if authorIsChannel, case .peer = item.chatLocation {
adminBadgeString = NSAttributedString(string: " \(item.presentationData.strings.Channel_Status)", font: inlineBotPrefixFont, textColor: messageTheme.secondaryTextColor)
}
var viaSuffix: NSAttributedString?
@ -2240,9 +2242,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
var boostCount: Int = 0
for attribute in item.message.attributes {
if let attribute = attribute as? BoostCountMessageAttribute {
boostCount = attribute.count
if incoming {
for attribute in item.message.attributes {
if let attribute = attribute as? BoostCountMessageAttribute {
boostCount = attribute.count
}
}
}
@ -3181,9 +3185,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
var boostCount: Int = 0
for attribute in item.message.attributes {
if let attribute = attribute as? BoostCountMessageAttribute {
boostCount = attribute.count
if incoming {
for attribute in item.message.attributes {
if let attribute = attribute as? BoostCountMessageAttribute {
boostCount = attribute.count
}
}
}

View File

@ -433,7 +433,8 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
} else if let giveawayResults {
dateTextString = NSAttributedString(string: giveawayResults.winnersCount > 1 ? item.presentationData.strings.Chat_Giveaway_Message_WinnersInfo_Many : item.presentationData.strings.Chat_Giveaway_Message_WinnersInfo_One, font: textFont, textColor: textColor)
}
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none, hidesHeaders: true)
let hideHeaders = item.message.forwardInfo == nil
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: hideHeaders, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none, hidesHeaders: hideHeaders)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in
let sideInsets = layoutConstants.text.bubbleInsets.right * 2.0

View File

@ -350,11 +350,6 @@ public func groupStickerPackSetupController(context: AccountContext, updatedPres
if let completion {
completionImpl = { value in
completion(value)
if let _ = value {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = UndoOverlayController(presentationData: presentationData, content: .actionSucceeded(title: nil, text: presentationData.strings.Group_Appearance_EmojiPackUpdated, cancel: nil, destructive: false), elevatedLayout: false, action: { _ in return true })
presentControllerImpl?(controller, nil)
}
}
}

View File

@ -92,10 +92,12 @@ public final class MessageInputPanelComponent: Component {
enum Kind {
case text
case premiumRequired
case boostRequired
}
case text(String)
case premiumRequired(title: String, subtitle: String, action: () -> Void)
case boostRequired(title: String, subtitle: String, action: () -> Void)
var kind: Kind {
switch self {
@ -103,6 +105,8 @@ public final class MessageInputPanelComponent: Component {
return .text
case .premiumRequired:
return .premiumRequired
case .boostRequired:
return .boostRequired
}
}
@ -120,6 +124,12 @@ public final class MessageInputPanelComponent: Component {
} else {
return false
}
case let .boostRequired(title, subtitle, _):
if case .boostRequired(title, subtitle, _) = rhs {
return true
} else {
return false
}
}
}
}
@ -1093,7 +1103,7 @@ public final class MessageInputPanelComponent: Component {
contents = AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: text, font: Font.regular(17.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.3)))
))
case let .premiumRequired(title, subtitle, action):
case let .premiumRequired(title, subtitle, action), let .boostRequired(title, subtitle, action):
leftAlignment = true
contents = AnyComponent(PlainButtonComponent(
content: AnyComponent(VStack([

View File

@ -272,6 +272,10 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
controller.onStop()
}
}
}, error: { [weak self] _ in
if let self, let controller = self.getController() {
controller.completion(nil, nil, nil)
}
}))
}
@ -1686,7 +1690,7 @@ public class VideoMessageCameraScreen: ViewController {
self.audioSessionDisposable = self.context.sharedContext.mediaManager.audioSession.push(audioSessionType: audioSessionType, activate: { [weak self] _ in
if let self {
Queue.mainQueue().async {
Queue.mainQueue().after(0.05) {
self.node.setupCamera()
}
}

View File

@ -1,5 +1,5 @@
{
"app": "10.7.2",
"app": "10.8",
"bazel": "7.0.2",
"xcode": "15.2",
"macos": "13.0"