Merge branch 'develop' into aleksandrs/6963_multi_session_logout

This commit is contained in:
Aleksandrs Proskurins 2022-10-25 10:43:34 +03:00
commit af0a868d7a
28 changed files with 132 additions and 104 deletions

View file

@ -1,17 +1,17 @@
{
"images" : [
{
"filename" : "action_voice_message.png",
"filename" : "Microphone icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "action_voice_message@2x.png",
"filename" : "Microphone icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "action_voice_message@3x.png",
"filename" : "Microphone icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,17 +1,17 @@
{
"images" : [
{
"filename" : "voice_message_record_button_recording.png",
"filename" : "Microphone asset.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "voice_message_record_button_recording@2x.png",
"filename" : "Microphone asset@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "voice_message_record_button_recording@3x.png",
"filename" : "Microphone asset@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -32,6 +32,7 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
// MARK: - Properties
// MARK: Private
private var voiceMessageToolbarView: VoiceMessageToolbarView?
private var cancellables = Set<AnyCancellable>()
private var heightConstraint: NSLayoutConstraint!
private var hostingViewController: VectorHostingController!
@ -39,42 +40,6 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
private var viewModel: ComposerViewModelProtocol = ComposerViewModel(initialViewState: ComposerViewState())
// MARK: Public
var isEncryptionEnabled = false {
didSet {
updatePlaceholderText()
}
}
/// The current html content of the composer
var htmlContent: String {
get {
wysiwygViewModel.content.html
}
set {
wysiwygViewModel.setHtmlContent(newValue)
}
}
/// The display name to show when in edit/reply
var eventSenderDisplayName: String! {
get {
viewModel.eventSenderDisplayName
}
set {
viewModel.eventSenderDisplayName = newValue
}
}
/// Whether the composer is in send, reply or edit mode.
var sendMode: RoomInputToolbarViewSendMode {
get {
viewModel.sendMode.legacySendMode
}
set {
viewModel.sendMode = ComposerSendMode(from: newValue)
updatePlaceholderText()
}
}
override var placeholder: String! {
get {
@ -169,9 +134,22 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
switch result {
case .cancel:
self.toolbarViewDelegate?.roomInputToolbarViewDidTapCancel(self)
case let .contentDidChange(isEmpty):
setVoiceMessageToolbarIsHidden(!isEmpty)
}
}
private func setVoiceMessageToolbarIsHidden(_ isHidden: Bool) {
guard let voiceMessageToolbarView = voiceMessageToolbarView else { return }
UIView.transition(
with: voiceMessageToolbarView, duration: 0.15,
options: .transitionCrossDissolve,
animations: {
voiceMessageToolbarView.isHidden = isHidden
}
)
}
private func registerThemeServiceDidChangeThemeNotification() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
}
@ -185,12 +163,64 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp
wysiwygViewModel.textColor = theme.colors.primaryContent
}
// MARK: - RoomInputToolbarViewProtocol
// MARK: - HtmlRoomInputToolbarViewProtocol
var isEncryptionEnabled = false {
didSet {
updatePlaceholderText()
}
}
/// The current html content of the composer
var htmlContent: String {
get {
wysiwygViewModel.content.html
}
set {
wysiwygViewModel.setHtmlContent(newValue)
}
}
/// The display name to show when in edit/reply
var eventSenderDisplayName: String! {
get {
viewModel.eventSenderDisplayName
}
set {
viewModel.eventSenderDisplayName = newValue
}
}
/// Whether the composer is in send, reply or edit mode.
var sendMode: RoomInputToolbarViewSendMode {
get {
viewModel.sendMode.legacySendMode
}
set {
viewModel.sendMode = ComposerSendMode(from: newValue)
updatePlaceholderText()
}
}
/// Add the voice message toolbar to the composer
/// - Parameter voiceMessageToolbarView: the voice message toolbar UIView
func setVoiceMessageToolbarView(_ voiceMessageToolbarView: UIView!) {
// TODO embed the voice messages UI
if let voiceMessageToolbarView = voiceMessageToolbarView as? VoiceMessageToolbarView {
self.voiceMessageToolbarView = voiceMessageToolbarView
voiceMessageToolbarView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.deactivate(voiceMessageToolbarView.containersTopConstraints)
addSubview(voiceMessageToolbarView)
NSLayoutConstraint.activate(
[
hostingViewController.view.topAnchor.constraint(equalTo: voiceMessageToolbarView.topAnchor),
hostingViewController.view.leftAnchor.constraint(equalTo: voiceMessageToolbarView.leftAnchor),
hostingViewController.view.bottomAnchor.constraint(equalTo: voiceMessageToolbarView.bottomAnchor, constant: 4),
hostingViewController.view.rightAnchor.constraint(equalTo: voiceMessageToolbarView.rightAnchor)
]
)
} else {
self.voiceMessageToolbarView?.removeFromSuperview()
self.voiceMessageToolbarView = nil
}
}
func toolbarHeight() -> CGFloat {

View file

@ -88,6 +88,8 @@ class VoiceMessageToolbarView: PassthroughView, NibLoadable, Themable, UIGesture
@IBOutlet private var toastNotificationContainerView: UIView!
@IBOutlet private var toastNotificationLabel: UILabel!
@IBOutlet var containersTopConstraints: [NSLayoutConstraint]!
private var playbackView: VoiceMessagePlaybackView!
private var cancelLabelToRecordButtonDistance: CGFloat = 0.0

View file

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="VoiceMessageToolbarView" customModule="Riot" customModuleProvider="target">
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="VoiceMessageToolbarView" customModule="Element" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="544" height="72"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -19,7 +19,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XRB-CY-ijK" customClass="PassthroughView" customModule="Riot" customModuleProvider="target">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XRB-CY-ijK" customClass="PassthroughView" customModule="Element" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="544" height="72"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8fP-9K-WTa">
@ -71,7 +71,7 @@
<constraint firstAttribute="height" constant="152" id="li1-Bd-px2"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dyu-ha-046" customClass="PassthroughView" customModule="Riot" customModuleProvider="target">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dyu-ha-046" customClass="PassthroughView" customModule="Element" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="544" height="72"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="6FH-4Q-Z5e">
@ -267,12 +267,14 @@
<outlet property="slideToCancelLabel" destination="Ydw-Nb-zP6" id="l4Y-Eg-Qwc"/>
<outlet property="toastNotificationContainerView" destination="HDF-2Z-UHZ" id="8Ty-Gl-XnP"/>
<outlet property="toastNotificationLabel" destination="gZJ-ep-9Bz" id="soa-bs-C37"/>
<outletCollection property="containersTopConstraints" destination="XRb-zW-xdf" collectionClass="NSMutableArray" id="0JK-wT-gdZ"/>
<outletCollection property="containersTopConstraints" destination="tEJ-94-MLM" collectionClass="NSMutableArray" id="pY3-hI-Sda"/>
</connections>
<point key="canvasLocation" x="10.144927536231885" y="456.69642857142856"/>
</view>
</objects>
<resources>
<image name="chevron.left" catalog="system" width="96" height="128"/>
<image name="chevron.left" catalog="system" width="97" height="128"/>
<image name="room_context_menu_delete" width="24" height="24"/>
<image name="send_icon" width="36" height="36"/>
<image name="voice_message_cancel_gradient" width="104" height="47"/>

View file

@ -40,11 +40,13 @@ enum MockComposerScreenState: MockScreenState, CaseIterable {
viewModel.callback = { [weak viewModel, weak wysiwygviewModel] result in
guard let viewModel = viewModel else { return }
if viewModel.sendMode == .edit {
wysiwygviewModel?.setHtmlContent("")
}
switch result {
case .cancel: viewModel.sendMode = .send
case .cancel:
if viewModel.sendMode == .edit {
wysiwygviewModel?.setHtmlContent("")
}
viewModel.sendMode = .send
default: break
}
}

View file

@ -127,12 +127,14 @@ enum ComposerSendMode: Equatable {
case createDM
}
enum ComposerViewAction {
enum ComposerViewAction: Equatable {
case cancel
case contentDidChange(isEmpty: Bool)
}
enum ComposerViewModelResult {
enum ComposerViewModelResult: Equatable {
case cancel
case contentDidChange(isEmpty: Bool)
}

View file

@ -25,11 +25,10 @@ final class ComposerUITests: MockScreenTestCase {
let wysiwygTextView = app.textViews.allElementsBoundByIndex[0]
XCTAssertTrue(wysiwygTextView.exists)
let sendButton = app.buttons["sendButton"]
XCTAssertTrue(sendButton.exists)
XCTAssertFalse(sendButton.isEnabled)
XCTAssertFalse(sendButton.exists)
wysiwygTextView.tap()
wysiwygTextView.typeText("test")
XCTAssertTrue(sendButton.isEnabled)
XCTAssertTrue(sendButton.exists)
XCTAssertFalse(app.buttons["editButton"].exists)
}
@ -39,8 +38,7 @@ final class ComposerUITests: MockScreenTestCase {
let wysiwygTextView = app.textViews.allElementsBoundByIndex[0]
XCTAssertTrue(wysiwygTextView.exists)
let sendButton = app.buttons["sendButton"]
XCTAssertTrue(sendButton.exists)
XCTAssertFalse(sendButton.isEnabled)
XCTAssertFalse(sendButton.exists)
let cancelButton = app.buttons["cancelButton"]
XCTAssertTrue(cancelButton.exists)
@ -51,7 +49,7 @@ final class ComposerUITests: MockScreenTestCase {
wysiwygTextView.tap()
wysiwygTextView.typeText("test")
XCTAssertTrue(sendButton.isEnabled)
XCTAssertTrue(sendButton.exists)
XCTAssertFalse(app.buttons["editButton"].exists)
cancelButton.tap()
@ -66,8 +64,7 @@ final class ComposerUITests: MockScreenTestCase {
let wysiwygTextView = app.textViews.allElementsBoundByIndex[0]
XCTAssertTrue(wysiwygTextView.exists)
let editButton = app.buttons["editButton"]
XCTAssertTrue(editButton.exists)
XCTAssertFalse(editButton.isEnabled)
XCTAssertFalse(editButton.exists)
let cancelButton = app.buttons["cancelButton"]
XCTAssertTrue(cancelButton.exists)
@ -78,7 +75,7 @@ final class ComposerUITests: MockScreenTestCase {
wysiwygTextView.tap()
wysiwygTextView.typeText("test")
XCTAssertTrue(editButton.isEnabled)
XCTAssertTrue(editButton.exists)
XCTAssertFalse(app.buttons["sendButton"].exists)
cancelButton.tap()

View file

@ -26,7 +26,7 @@ struct Composer: View {
@Environment(\.theme) private var theme: ThemeSwiftUI
@State private var focused = false
@State private var isActionButtonEnabled = false
@State private var isActionButtonShowing = false
private let horizontalPadding: CGFloat = 12
private let borderHeight: CGFloat = 40
@ -148,7 +148,7 @@ struct Composer: View {
.resizable()
.foregroundColor(theme.colors.tertiaryContent)
.frame(width: 14, height: 14)
}
.frame(width: 36, height: 36)
.background(Circle().fill(theme.colors.system))
@ -159,16 +159,6 @@ struct Composer: View {
}
.frame(height: 44)
Spacer()
// ZStack {
// TODO: Add support for voice messages
// Button {
//
// } label: {
// Image(Asset.Images.voiceMessageRecordButtonDefault.name)
// .foregroundColor(theme.colors.tertiaryContent)
// }
// .isHidden(showSendButton)
// .isHidden(true)
Button {
sendMessageAction(wysiwygViewModel.content)
wysiwygViewModel.clearContent()
@ -181,18 +171,18 @@ struct Composer: View {
}
.frame(width: 36, height: 36)
.padding(.leading, 8)
.disabled(!isActionButtonEnabled)
.opacity(isActionButtonEnabled ? 1 : 0.3)
.animation(.easeInOut(duration: 0.15), value: isActionButtonEnabled)
.isHidden(!isActionButtonShowing)
.accessibilityIdentifier(actionButtonAccessibilityIdentifier)
.accessibilityLabel(VectorL10n.send)
.onChange(of: wysiwygViewModel.isContentEmpty) { empty in
isActionButtonEnabled = !empty
.onChange(of: wysiwygViewModel.isContentEmpty) { isEmpty in
viewModel.send(viewAction: .contentDidChange(isEmpty: isEmpty))
withAnimation(.easeInOut(duration: 0.15)) {
isActionButtonShowing = !isEmpty
}
}
}
.padding(.horizontal, 12)
.padding(.bottom, 4)
.animation(.none)
}
}
}

View file

@ -60,6 +60,8 @@ final class ComposerViewModel: ComposerViewModelType, ComposerViewModelProtocol
switch viewAction {
case .cancel:
callback?(.cancel)
case let .contentDidChange(isEmpty):
callback?(.contentDidChange(isEmpty: isEmpty))
}
}
}

View file

@ -58,7 +58,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .inactive, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: expectedItems,
sessionItems: expectedItems,
header: inactiveSectionHeader,
emptyItemsTitle: VectorL10n.userOtherSessionNoInactiveSessions,
allItemsSelected: false)
@ -74,7 +74,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: false)
@ -90,7 +90,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .unverified, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: expectedItems,
sessionItems: expectedItems,
header: unverifiedSectionHeader,
emptyItemsTitle: VectorL10n.userOtherSessionNoUnverifiedSessions,
allItemsSelected: false)
@ -106,7 +106,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .verified, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: expectedItems,
sessionItems: expectedItems,
header: verifiedSectionHeader,
emptyItemsTitle: VectorL10n.userOtherSessionNoVerifiedSessions,
allItemsSelected: false)
@ -120,7 +120,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .verified, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: [],
sessionItems: [],
header: verifiedSectionHeader,
emptyItemsTitle: VectorL10n.userOtherSessionNoVerifiedSessions,
allItemsSelected: false)
@ -134,7 +134,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .unverified, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: [],
sessionItems: [],
header: unverifiedSectionHeader,
emptyItemsTitle: VectorL10n.userOtherSessionNoUnverifiedSessions,
allItemsSelected: false)
@ -148,7 +148,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .inactive, isEditModeEnabled: false)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: "Title",
items: [],
sessionItems: [],
header: inactiveSectionHeader,
emptyItemsTitle: VectorL10n.userOtherSessionNoInactiveSessions,
allItemsSelected: false)
@ -167,7 +167,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: true)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: VectorL10n.userOtherSessionSelectedCount("2"),
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: true)
@ -186,7 +186,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: true)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: VectorL10n.userOtherSessionSelectedCount("0"),
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: false)
@ -204,7 +204,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: true)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: VectorL10n.userOtherSessionSelectedCount("1"),
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: false)
@ -222,7 +222,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: true)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: VectorL10n.userOtherSessionSelectedCount("2"),
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: true)
@ -240,7 +240,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: true)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: VectorL10n.userOtherSessionSelectedCount("0"),
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: false)
@ -261,7 +261,7 @@ class UserOtherSessionsViewModelTests: XCTestCase {
let bindings = UserOtherSessionsBindings(filter: .all, isEditModeEnabled: true)
let expectedState = UserOtherSessionsViewState(bindings: bindings,
title: VectorL10n.userOtherSessionSelectedCount("0"),
items: expectedItems,
sessionItems: expectedItems,
header: allSectionHeader,
emptyItemsTitle: "",
allItemsSelected: false)

View file

@ -35,7 +35,7 @@ enum UserOtherSessionsViewModelResult: Equatable {
struct UserOtherSessionsViewState: BindableState, Equatable {
var bindings: UserOtherSessionsBindings
var title: String
var items: [UserSessionListItemViewData]
var sessionItems: [UserSessionListItemViewData]
var header: UserOtherSessionsHeaderViewData
var emptyItemsTitle: String
var allItemsSelected: Bool

View file

@ -30,10 +30,10 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi
self.sessionInfos = sessionInfos
defaultTitle = title
let bindings = UserOtherSessionsBindings(filter: filter, isEditModeEnabled: false)
let items = filter.filterSessionInfos(sessionInfos: sessionInfos, selectedSessions: selectedSessions)
let sessionItems = filter.filterSessionInfos(sessionInfos: sessionInfos, selectedSessions: selectedSessions)
super.init(initialViewState: UserOtherSessionsViewState(bindings: bindings,
title: title,
items: items,
sessionItems: sessionItems,
header: filter.userOtherSessionsViewHeader,
emptyItemsTitle: filter.userOtherSessionsViewEmptyResultsTitle,
allItemsSelected: false))
@ -87,7 +87,7 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi
private func updateViewState() {
let currentFilter = state.bindings.filter
state.items = currentFilter.filterSessionInfos(sessionInfos: sessionInfos, selectedSessions: selectedSessions)
state.sessionItems = currentFilter.filterSessionInfos(sessionInfos: sessionInfos, selectedSessions: selectedSessions)
state.header = currentFilter.userOtherSessionsViewHeader
if state.bindings.isEditModeEnabled {

View file

@ -24,7 +24,7 @@ struct UserOtherSessions: View {
var body: some View {
ScrollView {
SwiftUI.Section {
if viewModel.viewState.items.isEmpty {
if viewModel.viewState.sessionItems.isEmpty {
noItemsView()
} else {
itemsView()
@ -81,7 +81,7 @@ struct UserOtherSessions: View {
private func itemsView() -> some View {
LazyVStack(spacing: 0) {
ForEach(viewModel.viewState.items) { viewData in
ForEach(viewModel.viewState.sessionItems) { viewData in
UserSessionListItem(viewData: viewData,
isEditModeEnabled: viewModel.isEditModeEnabled,
onBackgroundTap: { sessionId in viewModel.send(viewAction: .userOtherSessionSelected(sessionId: sessionId)) },

View file

@ -48,7 +48,7 @@ struct UserOtherSessionsToolbar: ToolbarContent {
} else {
filterMenuButton()
.offset(x: 12)
kebabMenu()
optionsMenu()
}
}
}
@ -77,7 +77,7 @@ struct UserOtherSessionsToolbar: ToolbarContent {
}
}
private func kebabMenu() -> some View {
private func optionsMenu() -> some View {
Button { } label: {
Menu {
Button {

1
changelog.d/6941.feature Normal file
View file

@ -0,0 +1 @@
Added voice message support to the Rich Text Composer