merged element-ios 1.10.5 into 4409_basis_update_1_10_5

This commit is contained in:
Arnfried Griesert
2023-03-16 12:19:26 +01:00
168 changed files with 2451 additions and 850 deletions
@@ -37,7 +37,7 @@ enum FormatType {
case unorderedList
case orderedList
case indent
case unIndent
case unindent
case inlineCode
case codeBlock
case quote
@@ -48,6 +48,18 @@ extension FormatType: CaseIterable, Identifiable {
var id: Self { self }
}
extension FormatType {
/// Return true if the format type is an indentation action.
var isIndentType: Bool {
switch self {
case .indent, .unindent:
return true
default:
return false
}
}
}
extension FormatItem: Identifiable {
var id: FormatType { type }
}
@@ -70,7 +82,7 @@ extension FormatItem {
return Asset.Images.numberedList.name
case .indent:
return Asset.Images.indentIncrease.name
case .unIndent:
case .unindent:
return Asset.Images.indentDecrease.name
case .inlineCode:
return Asset.Images.code.name
@@ -99,7 +111,7 @@ extension FormatItem {
return "orderedListButton"
case .indent:
return "indentListButton"
case .unIndent:
case .unindent:
return "unIndentButton"
case .inlineCode:
return "inlineCodeButton"
@@ -128,7 +140,7 @@ extension FormatItem {
return VectorL10n.wysiwygComposerFormatActionOrderedList
case .indent:
return VectorL10n.wysiwygComposerFormatActionIndent
case .unIndent:
case .unindent:
return VectorL10n.wysiwygComposerFormatActionUnIndent
case .inlineCode:
return VectorL10n.wysiwygComposerFormatActionInlineCode
@@ -160,8 +172,8 @@ extension FormatType {
return .orderedList
case .indent:
return .indent
case .unIndent:
return .unIndent
case .unindent:
return .unindent
case .inlineCode:
return .inlineCode
case .codeBlock:
@@ -191,8 +203,8 @@ extension FormatType {
return .orderedList
case .indent:
return .indent
case .unIndent:
return .unIndent
case .unindent:
return .unindent
case .inlineCode:
return .inlineCode
case .codeBlock:
@@ -158,4 +158,32 @@ final class ComposerUITests: MockScreenTestCase {
XCTAssertFalse(minimiseButton.exists)
XCTAssertTrue(maximiseButton.exists)
}
func testCreatingListDisplaysIndentButtons() throws {
app.goToScreenWithIdentifier(MockComposerScreenState.send.title)
XCTAssertFalse(composerToolbarButton(in: app, for: .indent).exists)
XCTAssertFalse(composerToolbarButton(in: app, for: .indent).exists)
// Create a list.
composerToolbarButton(in: app, for: .orderedList).tap()
XCTAssertTrue(composerToolbarButton(in: app, for: .indent).exists)
XCTAssertTrue(composerToolbarButton(in: app, for: .indent).exists)
// Remove the list
composerToolbarButton(in: app, for: .orderedList).tap()
XCTAssertFalse(composerToolbarButton(in: app, for: .indent).exists)
XCTAssertFalse(composerToolbarButton(in: app, for: .indent).exists)
}
}
private extension ComposerUITests {
/// Returns the button of the composer toolbar associated with given format type.
///
/// - Parameters:
/// - app: the running app
/// - formatType: format type to look for
/// - Returns: XCUIElement for the button
func composerToolbarButton(in app: XCUIApplication, for formatType: FormatType) -> XCUIElement {
// Note: state is irrelevant here, we're just building this to retrieve the accessibility identifier.
app.buttons[FormatItem(type: formatType, state: .enabled).accessibilityIdentifier]
}
}
@@ -71,12 +71,15 @@ struct Composer: View {
}
private var formatItems: [FormatItem] {
FormatType.allCases.map { type in
FormatItem(
type: type,
state: wysiwygViewModel.actionStates[type.composerAction] ?? .disabled
)
}
return FormatType.allCases
// Exclude indent type outside of lists.
.filter { wysiwygViewModel.isInList || !$0.isIndentType }
.map { type in
FormatItem(
type: type,
state: wysiwygViewModel.actionStates[type.composerAction] ?? .disabled
)
}
}
private var composerContainer: some View {
@@ -257,6 +260,13 @@ struct Composer: View {
}
}
private extension WysiwygComposerViewModel {
/// Return true if the selection of the composer is currently located in a list.
var isInList: Bool {
actionStates[.orderedList] == .reversed || actionStates[.unorderedList] == .reversed
}
}
// MARK: Previews
struct Composer_Previews: PreviewProvider {
@@ -41,12 +41,12 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin
let avatarData = showAvatar ? AvatarInput(
mxContentUri: room.summary.avatar,
matrixItemId: room.roomId,
displayName: room.summary.displayname
displayName: room.summary.displayName
) : nil
let viewModel = RoomNotificationSettingsSwiftUIViewModel(
roomNotificationService: roomNotificationService,
avatarData: avatarData,
displayName: room.summary.displayname,
displayName: room.summary.displayName,
roomEncrypted: room.summary.isEncrypted
)
let avatarService: AvatarServiceProtocol = AvatarService(mediaManager: room.mxSession.mediaManager)
@@ -15,6 +15,7 @@
//
import Foundation
import SwiftUI
@objcMembers
class TimelinePollProvider: NSObject {
@@ -45,7 +46,7 @@ class TimelinePollProvider: NSObject {
let parameters = TimelinePollCoordinatorParameters(session: session, room: room, pollEvent: event)
guard let coordinator = try? TimelinePollCoordinator(parameters: parameters) else {
return nil
return messageViewController(for: event)
}
coordinatorsForEventIdentifiers[event.eventId] = coordinator
@@ -62,3 +63,14 @@ class TimelinePollProvider: NSObject {
coordinatorsForEventIdentifiers.removeAll()
}
}
private extension TimelinePollProvider {
func messageViewController(for event: MXEvent) -> UIViewController? {
switch event.eventType {
case .pollEnd:
return VectorHostingController(rootView: TimelinePollMessageView(message: VectorL10n.pollTimelineReplyEndedPoll))
default:
return nil
}
}
}
@@ -0,0 +1,45 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
/// A view for showing polls' related messages whenever there aren't enough information to show a full poll in the timeline.
struct TimelinePollMessageView: View {
@Environment(\.theme) private var theme
private let imageSize: CGFloat = 16
let message: String
var body: some View {
HStack {
Image(uiImage: Asset.Images.pollHistory.image)
.resizable()
.frame(width: imageSize, height: imageSize)
Text(message)
.font(.system(size: 15))
.foregroundColor(theme.colors.primaryContent)
}
.padding(.vertical, 8)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct TimelinePollMessageView_Previews: PreviewProvider {
static var previews: some View {
TimelinePollMessageView(message: VectorL10n.pollTimelineReplyEndedPoll)
}
}
@@ -0,0 +1,50 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
struct RoomWaitingForMembers: View {
@Environment(\.theme) private var theme: ThemeSwiftUI
var body: some View {
ZStack {
HStack(alignment: .top) {
Image(uiImage: Asset.Images.membersListIcon.image)
VStack(alignment: .leading, spacing: 6) {
Text(VectorL10n.roomWaitingOtherParticipantsTitle(AppInfo.current.displayName))
.font(theme.fonts.bodySB)
.foregroundColor(theme.colors.primaryContent)
.frame(maxWidth: .infinity, alignment: .leading)
Text(VectorL10n.roomWaitingOtherParticipantsMessage(AppInfo.current.displayName))
.font(theme.fonts.caption1)
.foregroundColor(theme.colors.secondaryContent)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.padding(9)
.background(theme.colors.system)
.cornerRadius(4)
}
}
}
struct RoomWaitingForMembers_Previews: PreviewProvider {
static var previews: some View {
RoomWaitingForMembers()
.padding(16)
}
}