Skip to content

Commit

Permalink
Fix: text color of the last event description was incorrect.
Browse files Browse the repository at this point in the history
  • Loading branch information
nimau committed May 12, 2023
1 parent cc9bc24 commit b558d4c
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Riot/Managers/Theme/ThemeIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import Foundation

enum ThemeIdentifier: String, RawRepresentable {
enum ThemeIdentifier: String, RawRepresentable, CaseIterable {
case light = "default"
case dark = "dark"
case black = "black"
Expand Down
2 changes: 1 addition & 1 deletion Riot/Managers/Theme/ThemeService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ extension ThemeService {
return nil
}
return ThemeIdentifier(rawValue: themeId)
}
}
}
24 changes: 23 additions & 1 deletion Riot/Modules/Common/Recents/Views/RecentTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,29 @@ - (void)render:(MXKCellData *)cellData
// Manage lastEventAttributedTextMessage optional property
if (!roomCellData.roomSummary.spaceChildInfo && [roomCellData respondsToSelector:@selector(lastEventAttributedTextMessage)])
{
self.lastEventDescription.attributedText = roomCellData.lastEventAttributedTextMessage;
// Attempt to correct the attributed string colors to match the current theme
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:roomCellData.lastEventAttributedTextMessage];
[attributedText enumerateAttribute:NSForegroundColorAttributeName
inRange:NSMakeRange(0, attributedText.length)
options:0
usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
if ([value isKindOfClass:UIColor.class])
{
UIColor *color = (UIColor*)value;
if (color)
{
UIColor *correctedColor = [color convertToCurrentTheme];
if (![color isEqual:correctedColor])
{
[attributedText addAttribute:NSForegroundColorAttributeName
value:correctedColor
range:range];
}
}
}
}];

self.lastEventDescription.attributedText = attributedText;
}
else
{
Expand Down
88 changes: 88 additions & 0 deletions Riot/Utils/ThemeColorConverter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//
// 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 Foundation

/// Utility struct to convert a color to its equivalent in a given theme
struct ThemeColorConverter {
private static var conversionTable: [String: UIColor] = [:]
private static let conversionTableQueue = DispatchQueue(label: "io.element.ThemeColorConverter.queue", qos: .userInteractive)

/// Tries to convert a color to its equivalent in the given theme
/// - Parameters:
/// - color: the color to convert
/// - targetTheme: destination theme
/// - Returns: the converted color or the original one if no match is found
static func convertColor(_ color: UIColor, to targetTheme: Theme) -> UIColor {
let conversionTableKey = computeColorConversionTableKey(color: color, theme: targetTheme)
if let cachedColor = conversionTable[conversionTableKey] {
return cachedColor
}

var resultColor = color

defer {
// Store the resulting color in the conversion table
conversionTableQueue.sync {
conversionTable[conversionTableKey] = resultColor
}
}

for themeIdentifier in ThemeIdentifier.allCases {
if themeIdentifier.rawValue == targetTheme.identifier {
continue
}
if let convertedColor = convertColor(color, from: ThemeService.shared().theme(withThemeId: themeIdentifier.rawValue), to: targetTheme) {
resultColor = convertedColor
break
}
}

return resultColor
}

/// Attempts to convert a color from one theme to another
/// - Parameters:
/// - color: the color to convert
/// - source: source Theme
/// - destination: destination Theme
/// - Returns: corresponding color or nil if not found
private static func convertColor(_ color: UIColor, from source: Theme, to destination: Theme) -> UIColor? {
let mirror = Mirror(reflecting: source.colors)
// If the source theme contains the same color value for several colors, the first one will be used.
if let colorName = mirror.children.first(where: {($0.value as? UIColor) == color})?.label {
return destination.colors.value(forKey: colorName) as? UIColor
}

return nil
}

private static func computeColorConversionTableKey(color: UIColor, theme: Theme) -> String {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
let hexValue = Int(r * 255) << 24 | Int(g * 255) << 16 | Int(b * 255) << 8 | Int(a * 255) << 0
return "\(theme.identifier)-\(String(format: "#%08x", hexValue))"
}
}

extension UIColor {
@objc func convertToCurrentTheme() -> UIColor {
return ThemeColorConverter.convertColor(self, to: ThemeService.shared().theme)
}
}
1 change: 1 addition & 0 deletions changelog.d/pr-7545.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix: The last event description text color now matches the active theme.

0 comments on commit b558d4c

Please sign in to comment.