Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New avatar colors + tests #22

Merged
merged 12 commits into from
Aug 31, 2023
19 changes: 19 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This workflow will build a Swift project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift

name: Tests

on:
pull_request:
branches: [ "main" ]

jobs:
tests:

runs-on: macos-13

steps:
- uses: actions/checkout@v3
- name: Run tests
run: xcodebuild test -scheme 'Compound' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14'

36 changes: 36 additions & 0 deletions Sources/Compound/Colors/CompoundColors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,26 @@ public struct CompoundColors {
public let bgSubtleSecondaryLevel0 = Color(UIColor { $0.isLight ? UIColor(compound.colorGray300) : UIColor(compound.colorThemeBg) })
public let bgCanvasDefaultLevel1 = Color(UIColor { $0.isLight ? UIColor(compound.colorThemeBg) : UIColor(compound.colorGray300) })

// MARK: - Avatar Colors
// Used to determine the background color and the foreground color of an avatar.

// Order matches the one from web
// https://github.com/vector-im/compound-web/blob/5dda11aa9733462fb8422968181275bc3e9b35e3/src/components/Avatar/Avatar.module.css#L64
internal let avatarColors: [AvatarColor] = [
.init(background: compound.colorBlue300, foreground: compound.colorBlue1200),
.init(background: compound.colorFuchsia300, foreground: compound.colorFuchsia1200),
.init(background: compound.colorGreen300, foreground: compound.colorGreen1200),
.init(background: compound.colorPink300, foreground: compound.colorPink1200),
.init(background: compound.colorOrange300, foreground: compound.colorOrange1200),
.init(background: compound.colorCyan300, foreground: compound.colorCyan1200),
.init(background: compound.colorPurple300, foreground: compound.colorPurple1200),
.init(background: compound.colorLime300, foreground: compound.colorLime1200)
]

public func avatarColor(for contentID: String) -> AvatarColor {
avatarColors[contentID.hashCode]
}

// MARK: - Awaiting Semantic Tokens

/// This token is a placeholder and hasn't been finalised.
Expand Down Expand Up @@ -125,3 +145,19 @@ private extension UITraitCollection {
/// Whether or not the trait collection contains a `userInterfaceStyle` of `.light`.
var isLight: Bool { userInterfaceStyle == .light }
}

public struct AvatarColor: Equatable {
let background: Color
let foreground: Color
}

private extension String {
/// Calculates a numeric hash same as Element Web
/// See original function here https://github.com/matrix-org/matrix-react-sdk/blob/321dd49db4fbe360fc2ff109ac117305c955b061/src/utils/FormattingUtils.js#L47
var hashCode: Int {
let characterCodeSum = self.reduce(0) { sum, character in
sum + Int(character.unicodeScalars.first?.value ?? 0)
}
return (characterCodeSum % Color.compound.avatarColors.count)
}
}
46 changes: 46 additions & 0 deletions Tests/CompoundTests/AvatarColorsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// File.swift
//
//
// Created by Mauro Romito on 31/08/23.
//

import Foundation

@testable import Compound
import SwiftUI
import XCTest

final class AvatarColorsTests: XCTestCase {
struct TestCase {
let input: String
private let webOutput: Int

// remember that web starts the index from 1 while we start from 0
var output: Int {
webOutput - 1
}

init(input: String, webOutput: Int) {
self.input = input
self.webOutput = webOutput
}
}

func testAvatarColorHash() {
// Match the tests with the web ones for consistency between the two platforms
// https://github.com/vector-im/compound-web/blob/5dda11aa9733462fb8422968181275bc3e9b35e3/src/components/Avatar/Avatar.test.tsx#L62
let testCases: [TestCase] = [
.init(input: "@bob:example.org", webOutput: 8),
.init(input: "@alice:example.org", webOutput: 3),
.init(input: "@charlie:example.org", webOutput: 5),
.init(input: "@dan:example.org", webOutput: 8),
.init(input: "@elena:example.org", webOutput: 2),
.init(input: "@fanny:example.org", webOutput: 1)
]

for testCase in testCases {
XCTAssertEqual(Color.compound.avatarColor(for: testCase.input), Color.compound.avatarColors[testCase.output])
}
}
}