mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
2cac381736
2
Makefile
2
Makefile
@ -3,7 +3,7 @@
|
||||
include Utils.makefile
|
||||
|
||||
|
||||
APP_VERSION="7.2.1"
|
||||
APP_VERSION="7.3"
|
||||
CORE_COUNT=$(shell sysctl -n hw.logicalcpu)
|
||||
CORE_COUNT_MINUS_ONE=$(shell expr ${CORE_COUNT} \- 1)
|
||||
|
||||
|
@ -244,7 +244,6 @@ official_apple_pay_merchants = [
|
||||
"merchant.sberbank.test.ph.telegra.Telegraph",
|
||||
"merchant.privatbank.test.telergramios",
|
||||
"merchant.privatbank.prod.telergram",
|
||||
"merchant.telegram.tranzzo.test",
|
||||
]
|
||||
|
||||
official_bundle_ids = [
|
||||
|
@ -2493,6 +2493,9 @@ Unused sets are archived when you add more.";
|
||||
"Call.CallInProgressMessage" = "Finish call with %1$@ and start a new one with %2$@?";
|
||||
"Call.ExternalCallInProgressMessage" = "Please finish the current call first.";
|
||||
|
||||
"Call.VoiceChatInProgressTitle" = "Voice Chat in Progress";
|
||||
"Call.VoiceChatInProgressMessage" = "Leave voice chat in %1$@ and start a new one with %2$@?";
|
||||
|
||||
"Call.Message" = "Message";
|
||||
|
||||
"UserInfo.TapToCall" = "Tap to make an end-to-end encrypted call";
|
||||
@ -5972,3 +5975,5 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.Panel.MembersSpeaking_any" = "%@ members speaking";
|
||||
|
||||
"ChannelInfo.CreateVoiceChat" = "Create Voice Chat";
|
||||
|
||||
"VoiceChat.AnonymousDisabledAlertText" = "Sorry, you can't join voice chat as an anonymous admin.";
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2583fa0bfd6909e7936da5b30e3547ba13e198dc
|
||||
Subproject commit f7f2b6d7c952f3cf6bdcedce6a0a2a40a27ff596
|
@ -51,6 +51,7 @@ BAZEL_OPTIONS=(\
|
||||
--spawn_strategy=standalone \
|
||||
--strategy=SwiftCompile=standalone \
|
||||
--features=swift.enable_batch_mode \
|
||||
--apple_generate_dsym \
|
||||
--swiftcopt=-j${CORE_COUNT_MINUS_ONE} \
|
||||
)
|
||||
|
||||
|
@ -81,7 +81,7 @@ COMMIT_ID="$(git rev-parse HEAD)"
|
||||
COMMIT_AUTHOR=$(git log -1 --pretty=format:'%an')
|
||||
if [ -z "$2" ]; then
|
||||
COMMIT_COUNT=$(git rev-list --count HEAD)
|
||||
COMMIT_COUNT="$(($COMMIT_COUNT+1000))"
|
||||
COMMIT_COUNT="$(($COMMIT_COUNT+2000))"
|
||||
BUILD_NUMBER="$COMMIT_COUNT"
|
||||
else
|
||||
BUILD_NUMBER="$2"
|
||||
|
@ -163,21 +163,29 @@ public struct PresentationGroupCallState: Equatable {
|
||||
case connected
|
||||
}
|
||||
|
||||
public enum DefaultParticipantMuteState {
|
||||
case unmuted
|
||||
case muted
|
||||
}
|
||||
|
||||
public var networkState: NetworkState
|
||||
public var canManageCall: Bool
|
||||
public var adminIds: Set<PeerId>
|
||||
public var muteState: GroupCallParticipantsContext.Participant.MuteState?
|
||||
public var defaultParticipantMuteState: DefaultParticipantMuteState?
|
||||
|
||||
public init(
|
||||
networkState: NetworkState,
|
||||
canManageCall: Bool,
|
||||
adminIds: Set<PeerId>,
|
||||
muteState: GroupCallParticipantsContext.Participant.MuteState?
|
||||
muteState: GroupCallParticipantsContext.Participant.MuteState?,
|
||||
defaultParticipantMuteState: DefaultParticipantMuteState?
|
||||
) {
|
||||
self.networkState = networkState
|
||||
self.canManageCall = canManageCall
|
||||
self.adminIds = adminIds
|
||||
self.muteState = muteState
|
||||
self.defaultParticipantMuteState = defaultParticipantMuteState
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +271,7 @@ public protocol PresentationGroupCall: class {
|
||||
|
||||
func toggleIsMuted()
|
||||
func setIsMuted(action: PresentationGroupCallMuteAction)
|
||||
func updateDefaultParticipantsAreMuted(isMuted: Bool)
|
||||
func setCurrentAudioOutput(_ output: AudioSessionOutput)
|
||||
|
||||
func updateMuteState(peerId: PeerId, isMuted: Bool)
|
||||
|
@ -69,8 +69,45 @@ public enum ContainedViewLayoutTransition {
|
||||
}
|
||||
}
|
||||
|
||||
public extension CGRect {
|
||||
var ensuredValid: CGRect {
|
||||
if !ASIsCGRectValidForLayout(CGRect(origin: CGPoint(), size: self.size)) {
|
||||
return CGRect()
|
||||
}
|
||||
if !ASIsCGPositionValidForLayout(self.origin) {
|
||||
return CGRect()
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
public extension ContainedViewLayoutTransition {
|
||||
func updateFrame(node: ASDisplayNode, frame: CGRect, force: Bool = false, beginWithCurrentState: Bool = false, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) {
|
||||
if frame.origin.x.isNaN {
|
||||
return
|
||||
}
|
||||
if frame.origin.y.isNaN {
|
||||
return
|
||||
}
|
||||
if frame.size.width.isNaN {
|
||||
return
|
||||
}
|
||||
if frame.size.width < 0.0 {
|
||||
return
|
||||
}
|
||||
if frame.size.height.isNaN {
|
||||
return
|
||||
}
|
||||
if frame.size.height < 0.0 {
|
||||
return
|
||||
}
|
||||
if !ASIsCGRectValidForLayout(CGRect(origin: CGPoint(), size: frame.size)) {
|
||||
return
|
||||
}
|
||||
if !ASIsCGPositionValidForLayout(frame.origin) {
|
||||
return
|
||||
}
|
||||
|
||||
if node.frame.equalTo(frame) && !force {
|
||||
completion?(true)
|
||||
} else {
|
||||
|
@ -443,6 +443,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
if origin == nil {
|
||||
self.editButton.isHidden = true
|
||||
self.deleteButton.isHidden = true
|
||||
self.editButton.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ private enum AdjacentEntryGroupInfo {
|
||||
|
||||
private func getAdjacentEntryGroupInfo(_ entry: IntermediateMessageHistoryEntry?, key: Int64) -> (IntermediateMessageHistoryEntry?, AdjacentEntryGroupInfo) {
|
||||
if let entry = entry {
|
||||
if let groupingKey = entry.message.groupingKey {
|
||||
if let groupingKey = entry.message.groupingKey, let groupInfo = entry.message.groupInfo {
|
||||
if groupingKey == key {
|
||||
if let groupInfo = entry.message.groupInfo {
|
||||
return (entry, .sameGroup(groupInfo))
|
||||
|
@ -21,7 +21,8 @@ private extension PresentationGroupCallState {
|
||||
networkState: .connecting,
|
||||
canManageCall: false,
|
||||
adminIds: Set(),
|
||||
muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true)
|
||||
muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true),
|
||||
defaultParticipantMuteState: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -389,7 +390,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .call(isTerminated):
|
||||
case let .call(isTerminated, _):
|
||||
if isTerminated {
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}
|
||||
@ -497,10 +498,16 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if let clientParams = joinCallResult.callInfo.clientParams {
|
||||
strongSelf.updateSessionState(internalState: .estabilished(info: joinCallResult.callInfo, clientParams: clientParams, localSsrc: ssrc, initialState: joinCallResult.state), audioSessionControl: strongSelf.audioSessionControl)
|
||||
}
|
||||
}, error: { _ in
|
||||
}, error: { error in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if case .anonymousNotAllowed = error {
|
||||
let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.accountContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.VoiceChat_AnonymousDisabledAlertText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})
|
||||
]), on: .root, blockInteraction: false, completion: {})
|
||||
}
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}))
|
||||
}))
|
||||
@ -573,6 +580,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
self.summaryInfoState.set(.single(SummaryInfoState(info: callInfo)))
|
||||
|
||||
self.stateValue.canManageCall = initialState.isCreator || initialState.adminIds.contains(self.accountContext.account.peerId)
|
||||
if self.stateValue.canManageCall && initialState.defaultParticipantsAreMuted.canChange {
|
||||
self.stateValue.defaultParticipantMuteState = initialState.defaultParticipantsAreMuted.isMuted ? .muted : .unmuted
|
||||
}
|
||||
|
||||
self.ssrcMapping.removeAll()
|
||||
var ssrcs: [UInt32] = []
|
||||
@ -634,6 +644,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
strongSelf.stateValue.adminIds = state.adminIds
|
||||
|
||||
if (state.isCreator || state.adminIds.contains(strongSelf.accountContext.account.peerId)) && state.defaultParticipantsAreMuted.canChange {
|
||||
strongSelf.stateValue.defaultParticipantMuteState = state.defaultParticipantsAreMuted.isMuted ? .muted : .unmuted
|
||||
}
|
||||
|
||||
strongSelf.summaryParticipantsState.set(.single(SummaryParticipantsState(
|
||||
participantCount: state.totalCount,
|
||||
topParticipants: topParticipants,
|
||||
@ -690,14 +704,29 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if terminateIfPossible {
|
||||
self.leaveDisposable.set((stopGroupCall(account: self.account, peerId: self.peerId, callId: callInfo.id, accessHash: callInfo.accessHash)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
self?._canBeRemoved.set(.single(true))
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.callContext?.stop()
|
||||
strongSelf.callContext = nil
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}))
|
||||
} else {
|
||||
self.leaveDisposable.set((leaveGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, source: localSsrc)
|
||||
|> deliverOnMainQueue).start(error: { [weak self] _ in
|
||||
self?._canBeRemoved.set(.single(true))
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.callContext?.stop()
|
||||
strongSelf.callContext = nil
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}, completed: { [weak self] in
|
||||
self?._canBeRemoved.set(.single(true))
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.callContext?.stop()
|
||||
strongSelf.callContext = nil
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
@ -900,4 +929,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateDefaultParticipantsAreMuted(isMuted: Bool) {
|
||||
self.participantsContext?.updateDefaultParticipantsAreMuted(isMuted: isMuted)
|
||||
}
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
default:
|
||||
if peer.id != strongSelf.context.account.peerId {
|
||||
if let callState = strongSelf.callState, (callState.canManageCall || callState.adminIds.contains(strongSelf.context.account.peerId)) {
|
||||
if let callState = strongSelf.callState, (callState.canManageCall || callState.adminIds.contains(strongSelf.context.account.peerId)), !callState.adminIds.contains(peer.id) {
|
||||
if let muteState = entry.muteState, !muteState.canUnmute {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_UnmutePeer, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Call/Context Menu/Unmute"), color: theme.actionSheet.primaryTextColor)
|
||||
@ -613,17 +613,44 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
/*items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_SpeakPermissionEveryone, icon: { theme in
|
||||
|
||||
if let callState = strongSelf.callState, callState.canManageCall, let defaultParticipantMuteState = callState.defaultParticipantMuteState {
|
||||
let isMuted = defaultParticipantMuteState == .muted
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_SpeakPermissionEveryone, icon: { theme in
|
||||
if isMuted {
|
||||
return nil
|
||||
} else {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.actionSheet.primaryTextColor)
|
||||
}
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.call.updateDefaultParticipantsAreMuted(isMuted: false)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_SpeakPermissionAdmin, icon: { _ in return nil}, action: { _, f in
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_SpeakPermissionAdmin, icon: { theme in
|
||||
if !isMuted {
|
||||
return nil
|
||||
} else {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.actionSheet.primaryTextColor)
|
||||
}
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.call.updateDefaultParticipantsAreMuted(isMuted: true)
|
||||
})))
|
||||
items.append(.separator)*/
|
||||
}
|
||||
|
||||
if !items.isEmpty {
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_Share, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
@ -698,7 +725,7 @@ public final class VoiceChatController: ViewController {
|
||||
super.didLoad()
|
||||
|
||||
let titleView = VoiceChatControllerTitleView(theme: self.presentationData.theme)
|
||||
titleView.set(title: "Voice Chat", subtitle: "connecting")
|
||||
titleView.set(title: self.presentationData.strings.VoiceChat_Title, subtitle: self.presentationData.strings.SocksProxySetup_ProxyStatusConnecting)
|
||||
self.controller?.navigationItem.titleView = titleView
|
||||
|
||||
let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.actionButtonPressGesture(_:)))
|
||||
|
@ -2970,11 +2970,24 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
return current
|
||||
}
|
||||
})
|
||||
|
||||
switch call {
|
||||
case let .groupCall(flags, _, _, _, _, _):
|
||||
let isMuted = (flags & (1 << 1)) != 0
|
||||
let canChange = (flags & (1 << 2)) != 0
|
||||
let defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: isMuted)
|
||||
updatedGroupCallParticipants.append((
|
||||
info.id,
|
||||
.call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted)
|
||||
))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
case let .groupCallDiscarded(callId, _, _):
|
||||
updatedGroupCallParticipants.append((
|
||||
callId,
|
||||
.call(isTerminated: true)
|
||||
.call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false))
|
||||
))
|
||||
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
|
@ -244,6 +244,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
||||
nextParticipantsFetchOffset: nextParticipantsFetchOffset,
|
||||
adminIds: Set(),
|
||||
isCreator: false,
|
||||
defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false),
|
||||
totalCount: totalCount,
|
||||
version: version
|
||||
)
|
||||
@ -254,6 +255,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
||||
|
||||
public enum JoinGroupCallError {
|
||||
case generic
|
||||
case anonymousNotAllowed
|
||||
}
|
||||
|
||||
public struct JoinGroupCallResult {
|
||||
@ -267,7 +269,10 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
return account.network.request(Api.functions.phone.joinGroupCall(flags: flags, call: .inputGroupCall(id: callId, accessHash: accessHash), params: .dataJSON(data: joinPayload)))
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
|> mapError { error -> JoinGroupCallError in
|
||||
if error.errorDescription == "GROUP_CALL_ANONYMOUS_FORBIDDEN" {
|
||||
return .anonymousNotAllowed
|
||||
}
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<JoinGroupCallResult, JoinGroupCallError> in
|
||||
@ -318,6 +323,16 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
||||
switch update {
|
||||
case let .updateGroupCall(_, call):
|
||||
maybeParsedCall = GroupCallInfo(call)
|
||||
|
||||
switch call {
|
||||
case let .groupCall(flags, _, _, _, _, _):
|
||||
let isMuted = (flags & (1 << 1)) != 0
|
||||
let canChange = (flags & (1 << 2)) != 0
|
||||
state.defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: canChange)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
break loop
|
||||
default:
|
||||
break
|
||||
@ -521,10 +536,16 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
public struct State: Equatable {
|
||||
public struct DefaultParticipantsAreMuted: Equatable {
|
||||
public var isMuted: Bool
|
||||
public var canChange: Bool
|
||||
}
|
||||
|
||||
public var participants: [Participant]
|
||||
public var nextParticipantsFetchOffset: String?
|
||||
public var adminIds: Set<PeerId>
|
||||
public var isCreator: Bool
|
||||
public var defaultParticipantsAreMuted: DefaultParticipantsAreMuted
|
||||
public var totalCount: Int
|
||||
public var version: Int32
|
||||
}
|
||||
@ -578,7 +599,7 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
case state(update: StateUpdate)
|
||||
case call(isTerminated: Bool)
|
||||
case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted)
|
||||
}
|
||||
|
||||
private let account: Account
|
||||
@ -627,6 +648,8 @@ public final class GroupCallParticipantsContext {
|
||||
private let updatesDisposable = MetaDisposable()
|
||||
private var activitiesDisposable: Disposable?
|
||||
|
||||
private let updateDefaultMuteDisposable = MetaDisposable()
|
||||
|
||||
public init(account: Account, peerId: PeerId, id: Int64, accessHash: Int64, state: State) {
|
||||
self.account = account
|
||||
self.id = id
|
||||
@ -699,6 +722,7 @@ public final class GroupCallParticipantsContext {
|
||||
nextParticipantsFetchOffset: strongSelf.stateValue.state.nextParticipantsFetchOffset,
|
||||
adminIds: strongSelf.stateValue.state.adminIds,
|
||||
isCreator: strongSelf.stateValue.state.isCreator,
|
||||
defaultParticipantsAreMuted: strongSelf.stateValue.state.defaultParticipantsAreMuted,
|
||||
totalCount: strongSelf.stateValue.state.totalCount,
|
||||
version: strongSelf.stateValue.state.version
|
||||
),
|
||||
@ -712,6 +736,7 @@ public final class GroupCallParticipantsContext {
|
||||
self.disposable.dispose()
|
||||
self.updatesDisposable.dispose()
|
||||
self.activitiesDisposable?.dispose()
|
||||
self.updateDefaultMuteDisposable.dispose()
|
||||
}
|
||||
|
||||
public func addUpdates(updates: [Update]) {
|
||||
@ -719,6 +744,8 @@ public final class GroupCallParticipantsContext {
|
||||
for update in updates {
|
||||
if case let .state(update) = update {
|
||||
stateUpdates.append(update)
|
||||
} else if case let .call(_, defaultParticipantsAreMuted) = update {
|
||||
self.stateValue.state.defaultParticipantsAreMuted = defaultParticipantsAreMuted
|
||||
}
|
||||
}
|
||||
|
||||
@ -831,6 +858,7 @@ public final class GroupCallParticipantsContext {
|
||||
let nextParticipantsFetchOffset = strongSelf.stateValue.state.nextParticipantsFetchOffset
|
||||
let adminIds = strongSelf.stateValue.state.adminIds
|
||||
let isCreator = strongSelf.stateValue.state.isCreator
|
||||
let defaultParticipantsAreMuted = strongSelf.stateValue.state.defaultParticipantsAreMuted
|
||||
|
||||
updatedParticipants.sort()
|
||||
for i in 0 ..< updatedParticipants.count {
|
||||
@ -848,6 +876,7 @@ public final class GroupCallParticipantsContext {
|
||||
nextParticipantsFetchOffset: nextParticipantsFetchOffset,
|
||||
adminIds: adminIds,
|
||||
isCreator: isCreator,
|
||||
defaultParticipantsAreMuted: defaultParticipantsAreMuted,
|
||||
totalCount: updatedTotalCount,
|
||||
version: update.version
|
||||
),
|
||||
@ -949,6 +978,22 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
public func updateDefaultParticipantsAreMuted(isMuted: Bool) {
|
||||
if isMuted == self.stateValue.state.defaultParticipantsAreMuted.isMuted {
|
||||
return
|
||||
}
|
||||
self.stateValue.state.defaultParticipantsAreMuted.isMuted = isMuted
|
||||
|
||||
|
||||
self.updateDefaultMuteDisposable.set((self.account.network.request(Api.functions.phone.toggleGroupCallSettings(flags: 1 << 0, call: .inputGroupCall(id: self.id, accessHash: self.accessHash), joinMuted: isMuted ? .boolTrue : .boolFalse))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] updates in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.account.stateManager.addUpdates(updates)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
extension GroupCallParticipantsContext.Update.StateUpdate {
|
||||
|
@ -639,6 +639,11 @@ extension StoreMessage {
|
||||
if (flags & (1 << 4)) != 0 {
|
||||
notificationFlags.insert(.personal)
|
||||
}
|
||||
if (flags & (1 << 4)) != 0 {
|
||||
notificationFlags.insert(.personal)
|
||||
let notConsumed = (flags & (1 << 5)) != 0
|
||||
attributes.append(ConsumablePersonalMentionMessageAttribute(consumed: !notConsumed, pending: false))
|
||||
}
|
||||
if (flags & (1 << 13)) != 0 {
|
||||
notificationFlags.insert(.muted)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -643,6 +643,17 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
|
||||
if data.canEdit && !isPinnedMessages {
|
||||
var mediaReference: AnyMediaReference?
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage, let _ = largestImageRepresentation(image.representations) {
|
||||
mediaReference = ImageMediaReference.standalone(media: image).abstract
|
||||
break
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
mediaReference = FileMediaReference.standalone(media: file).abstract
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_MessageDialogEdit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, f in
|
||||
|
@ -1477,7 +1477,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
|
||||
if let mosaicRange = mosaicRange {
|
||||
let maxSize = layoutConstants.image.maxDimensions.fittedToWidthOrSmaller(maximumContentWidth - layoutConstants.image.bubbleInsets.left - layoutConstants.image.bubbleInsets.right)
|
||||
let (innerFramesAndPositions, innerSize) = chatMessageBubbleMosaicLayout(maxSize: maxSize, itemSizes: contentPropertiesAndLayouts[mosaicRange].map { $0.0 ?? CGSize(width: 256.0, height: 256.0) })
|
||||
let (innerFramesAndPositions, innerSize) = chatMessageBubbleMosaicLayout(maxSize: maxSize, itemSizes: contentPropertiesAndLayouts[mosaicRange].map { item in
|
||||
guard let size = item.0, size.width > 0.0, size.height > 0 else {
|
||||
return CGSize(width: 256.0, height: 256.0)
|
||||
}
|
||||
return size
|
||||
})
|
||||
|
||||
let framesAndPositions = innerFramesAndPositions.map { ($0.0.offsetBy(dx: layoutConstants.image.bubbleInsets.left, dy: layoutConstants.image.bubbleInsets.top), $0.1) }
|
||||
|
||||
|
@ -680,7 +680,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
|
||||
let arguments = TransformImageArguments(corners: corners, imageSize: drawingSize, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets(), resizeMode: isInlinePlayableVideo ? .fill(.black) : .blurBackground, emptyColor: emptyColor, custom: patternArguments)
|
||||
|
||||
let imageFrame = CGRect(origin: CGPoint(x: -arguments.insets.left, y: -arguments.insets.top), size: arguments.drawingSize)
|
||||
let imageFrame = CGRect(origin: CGPoint(x: -arguments.insets.left, y: -arguments.insets.top), size: arguments.drawingSize).ensuredValid
|
||||
|
||||
let imageApply = imageLayout(arguments)
|
||||
|
||||
|
@ -24,6 +24,7 @@ objc_library(
|
||||
copts = [
|
||||
"-Dpixman_region_selfcheck(x)=1",
|
||||
"-DLOTTIE_DISABLE_ARM_NEON=1",
|
||||
"-DLOTTIE_THREAD_SAFE=1",
|
||||
"-DLOTTIE_IMAGE_MODULE_DISABLED=1",
|
||||
"-I{}".format(package_name()),
|
||||
"-I{}/rlottie/inc".format(package_name()),
|
||||
|
Loading…
x
Reference in New Issue
Block a user