Voice Chat Fixes

This commit is contained in:
Ilya Laktyushin 2021-04-09 21:17:26 +03:00
parent 045d102294
commit 8c587463fd
9 changed files with 54 additions and 27 deletions

View File

@ -6321,6 +6321,13 @@ Sorry for the inconvenience.";
"VoiceChat.EditBioSave" = "Save"; "VoiceChat.EditBioSave" = "Save";
"VoiceChat.EditBioSuccess" = "Your bio is changed."; "VoiceChat.EditBioSuccess" = "Your bio is changed.";
"VoiceChat.EditDescription" = "Edit Description";
"VoiceChat.EditDescriptionTitle" = "Description";
"VoiceChat.EditDescriptionText" = "Any details such as age, occupation or city.";
"VoiceChat.EditDescriptionPlaceholder" = "Description";
"VoiceChat.EditDescriptionSave" = "Save";
"VoiceChat.EditDescriptionSuccess" = "Description is changed.";
"VoiceChat.SendPublicLinkText" = "%1$@ isn't a member of \"%2$@\" yet. Send them a public invite link instead?"; "VoiceChat.SendPublicLinkText" = "%1$@ isn't a member of \"%2$@\" yet. Send them a public invite link instead?";
"VoiceChat.SendPublicLinkSend" = "Send"; "VoiceChat.SendPublicLinkSend" = "Send";

View File

@ -595,6 +595,13 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
self.animateOut(shared: true, completion: { self.animateOut(shared: true, completion: {
}) })
self.completed?(peerIds) self.completed?(peerIds)
Queue.mainQueue().after(0.44) {
if self.hapticFeedback == nil {
self.hapticFeedback = HapticFeedback()
}
self.hapticFeedback?.success()
}
} }
let fromForeignApp = self.fromForeignApp let fromForeignApp = self.fromForeignApp
self.shareDisposable.set((signal self.shareDisposable.set((signal

View File

@ -17,11 +17,14 @@ private let green = UIColor(rgb: 0x33c659)
private let activeBlue = UIColor(rgb: 0x00a0b9) private let activeBlue = UIColor(rgb: 0x00a0b9)
private let purple = UIColor(rgb: 0x3252ef) private let purple = UIColor(rgb: 0x3252ef)
private let pink = UIColor(rgb: 0xef436c) private let pink = UIColor(rgb: 0xef436c)
private let latePurple = UIColor(rgb: 0xaa56a6)
private let latePink = UIColor(rgb: 0xef476f)
private class CallStatusBarBackgroundNode: ASDisplayNode { private class CallStatusBarBackgroundNode: ASDisplayNode {
enum State { enum State {
case connecting case connecting
case cantSpeak case cantSpeak
case late
case active case active
case speaking case speaking
} }
@ -64,6 +67,8 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
targetColors = [green.cgColor, activeBlue.cgColor] targetColors = [green.cgColor, activeBlue.cgColor]
case .cantSpeak: case .cantSpeak:
targetColors = [purple.cgColor, pink.cgColor] targetColors = [purple.cgColor, pink.cgColor]
case .late:
targetColors = [latePurple.cgColor, latePink.cgColor]
} }
if CACurrentMediaTime() - self.initialTimestamp > 0.1 { if CACurrentMediaTime() - self.initialTimestamp > 0.1 {
@ -200,6 +205,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
private var currentGroupCallState: PresentationGroupCallSummaryState? private var currentGroupCallState: PresentationGroupCallSummaryState?
private var currentIsMuted = true private var currentIsMuted = true
private var currentCantSpeak = false private var currentCantSpeak = false
private var currentScheduleTimestamp: Int32?
private var currentMembers: PresentationGroupCallMembers? private var currentMembers: PresentationGroupCallMembers?
private var currentIsConnected = true private var currentIsConnected = true
@ -314,6 +320,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
} }
strongSelf.currentIsMuted = isMuted strongSelf.currentIsMuted = isMuted
strongSelf.currentCantSpeak = cantSpeak strongSelf.currentCantSpeak = cantSpeak
strongSelf.currentScheduleTimestamp = state?.callState.scheduleTimestamp
let currentIsConnected: Bool let currentIsConnected: Bool
if let state = state, case .connected = state.callState.networkState { if let state = state, case .connected = state.callState.networkState {
@ -351,6 +358,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
let textColor = UIColor.white let textColor = UIColor.white
var segments: [AnimatedCountLabelNode.Segment] = [] var segments: [AnimatedCountLabelNode.Segment] = []
var displaySpeakerSubtitle = false var displaySpeakerSubtitle = false
var isLate = false
if let presentationData = self.presentationData { if let presentationData = self.presentationData {
if let voiceChatTitle = self.currentGroupCallState?.info?.title, !voiceChatTitle.isEmpty { if let voiceChatTitle = self.currentGroupCallState?.info?.title, !voiceChatTitle.isEmpty {
@ -389,8 +397,9 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
let elapsedTime = scheduleTime - currentTime let elapsedTime = scheduleTime - currentTime
let timerText: String let timerText: String
if elapsedTime >= 86400 { if elapsedTime >= 86400 {
timerText = scheduledTimeIntervalString(strings: presentationData.strings, value: elapsedTime) timerText = presentationData.strings.VoiceChat_StatusStartsIn(scheduledTimeIntervalString(strings: presentationData.strings, value: elapsedTime)).0
} else if elapsedTime < 0 { } else if elapsedTime < 0 {
isLate = true
timerText = presentationData.strings.VoiceChat_StatusLateBy(textForTimeout(value: abs(elapsedTime))).0 timerText = presentationData.strings.VoiceChat_StatusLateBy(textForTimeout(value: abs(elapsedTime))).0
} else { } else {
timerText = presentationData.strings.VoiceChat_StatusStartsIn(textForTimeout(value: elapsedTime)).0 timerText = presentationData.strings.VoiceChat_StatusStartsIn(textForTimeout(value: elapsedTime)).0
@ -501,7 +510,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
let state: CallStatusBarBackgroundNode.State let state: CallStatusBarBackgroundNode.State
if self.currentIsConnected { if self.currentIsConnected {
if self.currentCantSpeak { if self.currentCantSpeak {
state = .cantSpeak state = isLate ? .late : .cantSpeak
} else if self.currentIsMuted { } else if self.currentIsMuted {
state = .active state = .active
} else { } else {

View File

@ -281,13 +281,9 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.dateTimeFormat = presentationData.dateTimeFormat self.dateTimeFormat = presentationData.dateTimeFormat
self.contentNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor self.contentNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
self.theme = presentationData.theme
self.separatorNode.backgroundColor = presentationData.theme.chat.historyNavigation.strokeColor self.separatorNode.backgroundColor = presentationData.theme.chat.historyNavigation.strokeColor
self.joinButtonTitleNode.attributedText = NSAttributedString(string: self.joinButtonTitleNode.attributedText?.string ?? "", font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: presentationData.theme.chat.inputPanel.actionControlForegroundColor) self.joinButtonTitleNode.attributedText = NSAttributedString(string: self.joinButtonTitleNode.attributedText?.string ?? "", font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.isScheduled ? .white : presentationData.theme.chat.inputPanel.actionControlForegroundColor)
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: presentationData.theme.chat.inputPanel.secondaryTextColor) self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: presentationData.theme.chat.inputPanel.secondaryTextColor)
self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme) self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme)
@ -305,23 +301,21 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
let pink = UIColor(rgb: 0xea436f) let pink = UIColor(rgb: 0xea436f)
let latePurple = UIColor(rgb: 0xaa56a6) let latePurple = UIColor(rgb: 0xaa56a6)
let latePink = UIColor(rgb: 0xef476f) let latePink = UIColor(rgb: 0xef476f)
let colors: [UIColor] let colors: [UIColor]
if self.isLate { if self.isLate {
colors = [latePurple, latePink] colors = [latePurple, latePink]
} else { } else {
colors = [purple, pink] colors = [purple, pink]
} }
if self.joinButtonBackgroundNode.image != nil, let snapshotView = self.joinButtonBackgroundNode.view.snapshotContentTree() { if self.joinButtonBackgroundNode.image != nil, let snapshotView = self.joinButtonBackgroundNode.view.snapshotContentTree() {
self.joinButtonBackgroundNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.joinButtonBackgroundNode.view) self.joinButtonBackgroundNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.joinButtonBackgroundNode.view)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 1.0, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview() snapshotView?.removeFromSuperview()
}) })
} }
self.joinButtonBackgroundNode.image = generateGradientImage(size: CGSize(width: 100.0, height: 1.0), colors: [purple, pink], locations: [0.0, 1.0], direction: .horizontal) self.joinButtonBackgroundNode.image = generateGradientImage(size: CGSize(width: 100.0, height: 1.0), colors: colors, locations: [0.0, 1.0], direction: .horizontal)
self.joinButtonBackgroundNode.backgroundColor = nil self.joinButtonBackgroundNode.backgroundColor = nil
} else { } else {
self.joinButtonBackgroundNode.image = nil self.joinButtonBackgroundNode.image = nil
@ -533,10 +527,10 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
isScheduled = true isScheduled = true
if let voiceChatTitle = self.currentData?.info.title { if let voiceChatTitle = self.currentData?.info.title {
title = voiceChatTitle title = voiceChatTitle
text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOn($0).0 }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrow($0).0 }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsToday($0).0 }, yesterdayFormatString: { $0 })) text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOn($0).0 }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrow($0).0 }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsToday($0).0 }, yesterdayFormatString: { $0 }))
} else { } else {
title = self.strings.Conversation_ScheduledVoiceChat title = self.strings.Conversation_ScheduledVoiceChat
text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOnShort($0).0 }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrowShort($0).0 }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTodayShort($0).0 }, yesterdayFormatString: { $0 })) text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOnShort($0).0 }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrowShort($0).0 }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTodayShort($0).0 }, yesterdayFormatString: { $0 }))
} }
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
@ -575,7 +569,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.updateJoinButton() self.updateJoinButton()
} }
self.joinButtonTitleNode.attributedText = NSAttributedString(string: joinText.uppercased(), font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.theme.chat.inputPanel.actionControlForegroundColor) self.joinButtonTitleNode.attributedText = NSAttributedString(string: joinText.uppercased(), font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: isScheduled ? .white : self.theme.chat.inputPanel.actionControlForegroundColor)
let joinButtonTitleSize = self.joinButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude)) let joinButtonTitleSize = self.joinButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude))
let joinButtonSize = CGSize(width: joinButtonTitleSize.width + 20.0, height: 28.0) let joinButtonSize = CGSize(width: joinButtonTitleSize.width + 20.0, height: 28.0)

View File

@ -1105,7 +1105,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
nextParticipantsFetchOffset: nil, nextParticipantsFetchOffset: nil,
adminIds: Set(), adminIds: Set(),
isCreator: false, isCreator: false,
defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: self.stateValue.defaultParticipantMuteState == .muted, canChange: false), defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: self.stateValue.defaultParticipantMuteState == .muted, canChange: true),
sortAscending: true, sortAscending: true,
recordingStartTimestamp: nil, recordingStartTimestamp: nil,
title: self.stateValue.title, title: self.stateValue.title,

View File

@ -656,11 +656,11 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
let previousValue = self.foregroundGradientLayer.startPoint let previousValue = self.foregroundGradientLayer.startPoint
let newValue: CGPoint let newValue: CGPoint
if self.maskBlobView.presentationAudioLevel > 0.22 { if self.maskBlobView.presentationAudioLevel > 0.22 {
newValue = CGPoint(x: CGFloat.random(in: 0.9 ..< 1.0), y: CGFloat.random(in: 0.1 ..< 0.35)) newValue = CGPoint(x: CGFloat.random(in: 0.9 ..< 1.0), y: CGFloat.random(in: 0.15 ..< 0.35))
} else if self.maskBlobView.presentationAudioLevel > 0.01 { } else if self.maskBlobView.presentationAudioLevel > 0.01 {
newValue = CGPoint(x: CGFloat.random(in: 0.77 ..< 0.95), y: CGFloat.random(in: 0.1 ..< 0.35)) newValue = CGPoint(x: CGFloat.random(in: 0.57 ..< 0.85), y: CGFloat.random(in: 0.15 ..< 0.45))
} else { } else {
newValue = CGPoint(x: CGFloat.random(in: 0.65 ..< 0.85), y: CGFloat.random(in: 0.1 ..< 0.45)) newValue = CGPoint(x: CGFloat.random(in: 0.6 ..< 0.75), y: CGFloat.random(in: 0.25 ..< 0.45))
} }
self.foregroundGradientLayer.startPoint = newValue self.foregroundGradientLayer.startPoint = newValue

View File

@ -2895,7 +2895,7 @@ public final class VoiceChatController: ViewController {
self.floatingHeaderOffset = offset self.floatingHeaderOffset = offset
if bottomEdge.isZero { if bottomEdge.isZero {
bottomEdge = self.listNode.frame.minY + 46.0 + 56.0 bottomEdge = self.listNode.frame.minY + 46.0 + 56.0 + 46
} }
let rawPanelOffset = offset + listTopInset - topPanelHeight let rawPanelOffset = offset + listTopInset - topPanelHeight
@ -3497,9 +3497,9 @@ public final class VoiceChatController: ViewController {
if let callState = self.callState { if let callState = self.callState {
if callState.scheduleTimestamp != nil && self.listNode.alpha > 0.0 { if callState.scheduleTimestamp != nil && self.listNode.alpha > 0.0 {
if !callState.canManageCall && (self.peer?.addressName?.isEmpty ?? true) { // if !callState.canManageCall && (self.peer?.addressName?.isEmpty ?? true) {
self.audioButton.isHidden = true // self.audioButton.isHidden = true
} // }
self.timerNode.isHidden = false self.timerNode.isHidden = false
self.listNode.alpha = 0.0 self.listNode.alpha = 0.0
self.listNode.isUserInteractionEnabled = false self.listNode.isUserInteractionEnabled = false
@ -3609,7 +3609,7 @@ public final class VoiceChatController: ViewController {
} }
} }
if canInvite && self.peer != nil { if canInvite && self.peer != nil {
entries.append(.invite(self.presentationData.theme, self.presentationData.strings, self.presentationData.strings.VoiceChat_InviteMember, inviteIsLink)) entries.append(.invite(self.presentationData.theme, self.presentationData.strings, inviteIsLink ? self.presentationData.strings.VoiceChat_Share : self.presentationData.strings.VoiceChat_InviteMember, inviteIsLink))
} }
for member in callMembers.0 { for member in callMembers.0 {

View File

@ -156,7 +156,7 @@ final class VoiceChatTimerNode: ASDisplayNode {
timer.start() timer.start()
} }
let subtitle = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime) let subtitle = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true)
self.titleNode.attributedText = NSAttributedString(string: elapsedTime < 0 ? self.strings.VoiceChat_LateBy : self.strings.VoiceChat_StartsIn, font: Font.with(size: 23.0, design: .round, weight: .semibold, traits: []), textColor: .white) self.titleNode.attributedText = NSAttributedString(string: elapsedTime < 0 ? self.strings.VoiceChat_LateBy : self.strings.VoiceChat_StartsIn, font: Font.with(size: 23.0, design: .round, weight: .semibold, traits: []), textColor: .white)
let titleSize = self.titleNode.updateLayout(size) let titleSize = self.titleNode.updateLayout(size)

View File

@ -157,7 +157,7 @@ public struct HumanReadableStringFormat {
} }
} }
public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, timestamp: Int32, format: HumanReadableStringFormat? = nil) -> String { public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, timestamp: Int32, alwaysShowTime: Bool = false, format: HumanReadableStringFormat? = nil) -> String {
var t: time_t = time_t(timestamp) var t: time_t = time_t(timestamp)
var timeinfo: tm = tm() var timeinfo: tm = tm()
localtime_r(&t, &timeinfo) localtime_r(&t, &timeinfo)
@ -168,7 +168,12 @@ public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTi
localtime_r(&now, &timeinfoNow) localtime_r(&now, &timeinfoNow)
if timeinfo.tm_year != timeinfoNow.tm_year { if timeinfo.tm_year != timeinfoNow.tm_year {
let string = "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat))" let string: String
if alwaysShowTime {
string = stringForMediumDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
} else {
string = stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)
}
return format?.dateFormatString(string) ?? string return format?.dateFormatString(string) ?? string
} }
@ -184,7 +189,12 @@ public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTi
} }
return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, format: format) return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min, format: format)
} else { } else {
let string = "\(stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat))" let string: String
if alwaysShowTime {
string = stringForMediumDate(timestamp: timestamp, strings: strings, dateTimeFormat: dateTimeFormat)
} else {
string = stringForTimestamp(day: timeinfo.tm_mday, month: timeinfo.tm_mon + 1, year: timeinfo.tm_year, dateTimeFormat: dateTimeFormat)
}
return format?.dateFormatString(string) ?? string return format?.dateFormatString(string) ?? string
} }
} }