mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
RTL and LTR mixed languages fix for optimal timestamp support (#1055)
* fix * fixed RTL and LTR timestamp for all the cases! also improved the testing * changelog * better and less convoluted solution * Update ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift Co-authored-by: Alfonso Grillo <alfogrillo@gmail.com> * pr suggestion and removed prefix in reality it creates more issues than improvements, and is not really needed --------- Co-authored-by: Alfonso Grillo <alfogrillo@gmail.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
extension LayoutDirection {
|
||||
var isolateLayoutUnicodeString: String {
|
||||
switch self {
|
||||
case .leftToRight:
|
||||
return "\u{2066}"
|
||||
case .rightToLeft:
|
||||
return "\u{2067}"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,15 +64,12 @@ extension String {
|
||||
}
|
||||
|
||||
extension String {
|
||||
static func generateBreakableWhitespaceEnd(whitespaceCount: Int, isRTL: Bool) -> String {
|
||||
static func generateBreakableWhitespaceEnd(whitespaceCount: Int, layoutDirection: LayoutDirection) -> String {
|
||||
guard whitespaceCount > 0 else {
|
||||
return ""
|
||||
}
|
||||
|
||||
var whiteSpaces = ""
|
||||
if isRTL {
|
||||
whiteSpaces = "\u{202e}"
|
||||
}
|
||||
var whiteSpaces = layoutDirection.isolateLayoutUnicodeString
|
||||
|
||||
// fixed size whitespace of size 1/3 em per character
|
||||
whiteSpaces += String(repeating: "\u{2004}", count: whitespaceCount)
|
||||
|
||||
@@ -64,6 +64,18 @@ struct TimelineItemStyler_Previews: PreviewProvider {
|
||||
return result
|
||||
}()
|
||||
|
||||
static let ltrString = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house!"))
|
||||
|
||||
static let rtlString = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת!"))
|
||||
|
||||
static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת! -- house!"))
|
||||
|
||||
static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת! -- house! -- באמת!"))
|
||||
|
||||
static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת!"))
|
||||
|
||||
static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת! -- house!"))
|
||||
|
||||
static var testView: some View {
|
||||
VStack {
|
||||
TextRoomTimelineView(timelineItem: sent)
|
||||
@@ -74,13 +86,37 @@ struct TimelineItemStyler_Previews: PreviewProvider {
|
||||
}
|
||||
}
|
||||
|
||||
static var languagesTestView: some View {
|
||||
VStack {
|
||||
TextRoomTimelineView(timelineItem: ltrString)
|
||||
TextRoomTimelineView(timelineItem: rtlString)
|
||||
TextRoomTimelineView(timelineItem: ltrStringThatContainsRtl)
|
||||
TextRoomTimelineView(timelineItem: rtlStringThatContainsLtr)
|
||||
TextRoomTimelineView(timelineItem: ltrStringThatFinishesInRtl)
|
||||
TextRoomTimelineView(timelineItem: rtlStringThatFinishesInLtr)
|
||||
}
|
||||
}
|
||||
|
||||
static var previews: some View {
|
||||
testView
|
||||
.environmentObject(viewModel.context)
|
||||
.environment(\.timelineStyle, .bubbles)
|
||||
.previewDisplayName("Bubbles")
|
||||
|
||||
testView
|
||||
.environmentObject(viewModel.context)
|
||||
.environment(\.timelineStyle, .plain)
|
||||
.previewDisplayName("Plain")
|
||||
|
||||
languagesTestView
|
||||
.environmentObject(viewModel.context)
|
||||
.environment(\.timelineStyle, .bubbles)
|
||||
.previewDisplayName("Bubbles LTR with different layout languages")
|
||||
|
||||
languagesTestView
|
||||
.environmentObject(viewModel.context)
|
||||
.environment(\.timelineStyle, .bubbles)
|
||||
.environment(\.layoutDirection, .rightToLeft)
|
||||
.previewDisplayName("Bubbles RTL with different layout languages")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ struct FormattedBodyText: View {
|
||||
|
||||
// These is needed to create the slightly off inlined timestamp effect
|
||||
private var additionalWhitespacesSuffix: String {
|
||||
.generateBreakableWhitespaceEnd(whitespaceCount: additionalWhitespacesCount, isRTL: layoutDirection == .rightToLeft)
|
||||
.generateBreakableWhitespaceEnd(whitespaceCount: additionalWhitespacesCount, layoutDirection: layoutDirection)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
||||
Reference in New Issue
Block a user