mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-14 03:40:00 +02:00
Merge pull request #7307 from vector-im/release/1.9.17/release
Release 1.9.17
This commit is contained in:
+12
@@ -1,3 +1,15 @@
|
||||
## Changes in 1.9.17 (2023-01-26)
|
||||
|
||||
🙌 Improvements
|
||||
|
||||
- Analytics: Ensure E2EE never tracks UnknownError ([#7304](https://github.com/vector-im/element-ios/pull/7304))
|
||||
|
||||
🐛 Bugfixes
|
||||
|
||||
- Fix a deadlock when updating the summary of a room that has a voice broadcast. ([#7300](https://github.com/vector-im/element-ios/pull/7300))
|
||||
- Space Switcher: Fix a bug where the avatars would all be the same. ([#7305](https://github.com/vector-im/element-ios/issues/7305))
|
||||
|
||||
|
||||
## Changes in 1.9.16 (2023-01-24)
|
||||
|
||||
✨ Features
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
//
|
||||
|
||||
// Version
|
||||
MARKETING_VERSION = 1.9.16
|
||||
CURRENT_PROJECT_VERSION = 1.9.16
|
||||
MARKETING_VERSION = 1.9.17
|
||||
CURRENT_PROJECT_VERSION = 1.9.17
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
|
||||
import AnalyticsEvents
|
||||
|
||||
/// Failure reasons as defined in https://docs.google.com/document/d/1es7cTCeJEXXfRCTRgZerAM2Wg5ZerHjvlpfTW-gsOfI.
|
||||
@objc enum DecryptionFailureReason: Int {
|
||||
case unspecified
|
||||
case olmKeysNotSent
|
||||
case olmIndexError
|
||||
case unexpected
|
||||
|
||||
var errorName: AnalyticsEvent.Error.Name {
|
||||
switch self {
|
||||
@@ -31,8 +29,6 @@ import AnalyticsEvents
|
||||
return .OlmKeysNotSentError
|
||||
case .olmIndexError:
|
||||
return .OlmIndexError
|
||||
case .unexpected:
|
||||
return .UnknownError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,12 +105,9 @@ NSString *const kDecryptionFailureTrackerAnalyticsCategory = @"e2e.failure";
|
||||
reason = DecryptionFailureReasonOlmIndexError;
|
||||
break;
|
||||
|
||||
case MXDecryptingErrorEncryptionNotEnabledCode:
|
||||
case MXDecryptingErrorUnableToDecryptCode:
|
||||
reason = DecryptionFailureReasonUnexpected;
|
||||
break;
|
||||
|
||||
default:
|
||||
// All other error codes will be tracked as `OlmUnspecifiedError` and will include `context` containing
|
||||
// the actual error code and localized description
|
||||
reason = DecryptionFailureReasonUnspecified;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ extension __MXCallHangupReason {
|
||||
switch self {
|
||||
case .userHangup:
|
||||
return .VoipUserHangup
|
||||
case .userBusy:
|
||||
// There is no dedicated analytics event for `userBusy` error
|
||||
return .UnknownError
|
||||
case .inviteTimeout:
|
||||
return .VoipInviteTimeout
|
||||
case .iceFailed:
|
||||
@@ -32,6 +35,9 @@ extension __MXCallHangupReason {
|
||||
case .unknownError:
|
||||
return .UnknownError
|
||||
default:
|
||||
MXLog.failure("Unknown or unhandled hangup reason", context: [
|
||||
"reason": rawValue
|
||||
])
|
||||
return .UnknownError
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +567,8 @@ static NSString *const kEventFormatterTimeFormat = @"HH:mm";
|
||||
return [self session:session
|
||||
updateRoomSummary:summary
|
||||
withVoiceBroadcastInfoStateEvent:lastVoiceBroadcastInfoEvent
|
||||
voiceBroadcastInfoStartedEvent:voiceBroadcastInfoStartedEvent roomState:roomState];
|
||||
voiceBroadcastInfoStartedEvent:voiceBroadcastInfoStartedEvent
|
||||
roomState:roomState];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,22 +625,8 @@ withVoiceBroadcastInfoStateEvent:lastVoiceBroadcastInfoEvent
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_group_enter(group);
|
||||
|
||||
__block MXEvent *voiceBroadcastInfoStartedEvent;
|
||||
|
||||
[session eventWithEventId:voiceBroadcastInfo.voiceBroadcastId inRoom:roomId success:^(MXEvent *resultEvent) {
|
||||
voiceBroadcastInfoStartedEvent = resultEvent;
|
||||
dispatch_group_leave(group);
|
||||
} failure:^(NSError *error) {
|
||||
MXLogErrorDetails(@"[EventFormatter] Fetch eventWithEventId with error = %@", error.description);
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
|
||||
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
||||
|
||||
return voiceBroadcastInfoStartedEvent;
|
||||
// Search for the event only in the store to avoid network calls while updating the room summary (this a synchronous process and we cannot delay it).
|
||||
return [mxSession.store eventWithEventId:voiceBroadcastInfo.voiceBroadcastId inRoom:roomId];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,11 @@ struct AvatarImage: View {
|
||||
var displayName: String?
|
||||
var size: AvatarSize
|
||||
|
||||
@State private var avatar: AvatarViewState = .empty
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
switch viewModel.viewState {
|
||||
switch avatar {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
case .placeholder(let firstCharacter, let colorIndex):
|
||||
@@ -42,13 +44,16 @@ struct AvatarImage: View {
|
||||
.frame(maxWidth: CGFloat(size.rawValue), maxHeight: CGFloat(size.rawValue))
|
||||
.clipShape(Circle())
|
||||
.onAppear {
|
||||
viewModel.loadAvatar(
|
||||
mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size
|
||||
)
|
||||
avatar = viewModel.placeholderAvatar(matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.colors.namesAndAvatars.count)
|
||||
viewModel.loadAvatar(mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size ) { newState in
|
||||
avatar = newState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,11 @@ struct SpaceAvatarImage: View {
|
||||
var displayName: String?
|
||||
var size: AvatarSize
|
||||
|
||||
@State private var avatar: AvatarViewState = .empty
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
switch viewModel.viewState {
|
||||
switch avatar {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
case .placeholder(let firstCharacter, let colorIndex):
|
||||
@@ -48,23 +50,27 @@ struct SpaceAvatarImage: View {
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
}
|
||||
}
|
||||
.onChange(of: displayName, perform: { value in
|
||||
viewModel.loadAvatar(
|
||||
mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: value,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size
|
||||
)
|
||||
})
|
||||
.onChange(of: displayName) { value in
|
||||
guard case .placeholder = avatar else { return }
|
||||
viewModel.loadAvatar(mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: value,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size) { newState in
|
||||
avatar = newState
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.loadAvatar(
|
||||
mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size
|
||||
)
|
||||
avatar = viewModel.placeholderAvatar(matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.colors.namesAndAvatars.count)
|
||||
viewModel.loadAvatar(mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size) { newState in
|
||||
avatar = newState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,22 @@ import Foundation
|
||||
final class AvatarViewModel: ObservableObject {
|
||||
private let avatarService: AvatarServiceProtocol
|
||||
|
||||
@Published private(set) var viewState = AvatarViewState.empty
|
||||
|
||||
init(avatarService: AvatarServiceProtocol) {
|
||||
self.avatarService = avatarService
|
||||
}
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
func placeholderAvatar(matrixItemId: String,
|
||||
displayName: String?,
|
||||
colorCount: Int) -> AvatarViewState {
|
||||
let placeholderViewModel = PlaceholderAvatarViewModel(displayName: displayName,
|
||||
matrixItemId: matrixItemId,
|
||||
colorCount: colorCount)
|
||||
|
||||
return .placeholder(placeholderViewModel.firstCharacterCapitalized, placeholderViewModel.stableColorIndex)
|
||||
}
|
||||
|
||||
/// Load an avatar
|
||||
/// - Parameters:
|
||||
/// - mxContentUri: The matrix content URI of the avatar.
|
||||
@@ -41,14 +49,10 @@ final class AvatarViewModel: ObservableObject {
|
||||
matrixItemId: String,
|
||||
displayName: String?,
|
||||
colorCount: Int,
|
||||
avatarSize: AvatarSize) {
|
||||
let placeholderViewModel = PlaceholderAvatarViewModel(displayName: displayName,
|
||||
matrixItemId: matrixItemId,
|
||||
colorCount: colorCount)
|
||||
|
||||
viewState = .placeholder(placeholderViewModel.firstCharacterCapitalized, placeholderViewModel.stableColorIndex)
|
||||
|
||||
avatarSize: AvatarSize,
|
||||
avatarCompletion: @escaping (AvatarViewState) -> Void) {
|
||||
guard let mxContentUri = mxContentUri, mxContentUri.count > 0 else {
|
||||
avatarCompletion(placeholderAvatar(matrixItemId: matrixItemId, displayName: displayName, colorCount: colorCount))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -56,8 +60,9 @@ final class AvatarViewModel: ObservableObject {
|
||||
.sink { completion in
|
||||
guard case let .failure(error) = completion else { return }
|
||||
UILog.error("[AvatarService] Failed to retrieve avatar", context: error)
|
||||
// No need to call the completion, there's nothing we can do and the error is logged.
|
||||
} receiveValue: { image in
|
||||
self.viewState = .avatar(image)
|
||||
avatarCompletion(.avatar(image))
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user