Commit 330f20d1 authored by Andreas Traczyk's avatar Andreas Traczyk

ui/ux: modernize fallback avatars

- Uses a color circle with a white capital letter(the first letter of
  the best id), instead of a character image as a default avatar.

- Maintains the color selection used by the GNOME, UWP, Win32, and
  OSX ring clients(a subset of Google's material.io colors).

Change-Id: I957abd2526e1d1e397f383b93720766e24a92aeb
Reviewed-by: Kateryna Kostiuk's avatarKateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
parent bf8889e4
......@@ -22,7 +22,6 @@
02B22DFF1DF755DB000358C9 /* AccountsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22DFE1DF755DB000358C9 /* AccountsService.swift */; };
02B22E091DF7585F000358C9 /* DaemonService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22E081DF7585F000358C9 /* DaemonService.swift */; };
02C9B63F1E1D4E8C00F82F0C /* ServiceEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C9B63E1E1D4E8C00F82F0C /* ServiceEvent.swift */; };
02E1A0251DDE4ABA00D75B59 /* String+Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866371D2304A700E06CE2 /* String+Bool.swift */; };
043866211D218B1100E06CE2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 043866201D218B1100E06CE2 /* AudioToolbox.framework */; };
043999F71D1C2D9D00E99CD9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043999F61D1C2D9D00E99CD9 /* AppDelegate.swift */; };
04399A031D1C2D9D00E99CD9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 04399A021D1C2D9D00E99CD9 /* Images.xcassets */; };
......@@ -186,6 +185,8 @@
62A88D371F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */; };
62A88D391F6C323500F8AB18 /* PresenceAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */; };
62A88D3B1F6C3ACC00F8AB18 /* PresenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */; };
62E55B6D1F758E6F00D3FEF4 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */; };
62E55B6F1F793ADE00D3FEF4 /* AvatarsColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -228,7 +229,6 @@
02B22E081DF7585F000358C9 /* DaemonService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DaemonService.swift; sourceTree = "<group>"; };
02C9B63E1E1D4E8C00F82F0C /* ServiceEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceEvent.swift; sourceTree = "<group>"; };
043866201D218B1100E06CE2 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
043866371D2304A700E06CE2 /* String+Bool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Bool.swift"; sourceTree = "<group>"; };
043999F31D1C2D9D00E99CD9 /* Ring.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ring.app; sourceTree = BUILT_PRODUCTS_DIR; };
043999F61D1C2D9D00E99CD9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
04399A021D1C2D9D00E99CD9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
......@@ -413,6 +413,8 @@
62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceAdapterDelegate.swift; sourceTree = "<group>"; };
62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PresenceAdapter.mm; sourceTree = "<group>"; };
62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceService.swift; sourceTree = "<group>"; };
62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Helpers.swift"; sourceTree = "<group>"; };
62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarsColors.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -613,7 +615,7 @@
isa = PBXGroup;
children = (
56BBC9BB1ED7161200CDAF8B /* Date+Helpers.swift */,
043866371D2304A700E06CE2 /* String+Bool.swift */,
62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */,
1A3D28A61F0EB9DB00B524EE /* Bool+String.swift */,
1A3D28A81F0EBF0200B524EE /* UIView+Ring.swift */,
1AABA7451F0FE9C000739605 /* UIColor+Ring.swift */,
......@@ -1025,6 +1027,7 @@
children = (
1ABE07C51F0D862D00D36361 /* Generated */,
564C445A1E8EA44E000F92B1 /* Durations.swift */,
62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */,
);
path = Constants;
sourceTree = "<group>";
......@@ -1255,7 +1258,6 @@
1A2D18AC1F29149D00B2C785 /* MeCoordinator.swift in Sources */,
1A2D18C51F29180700B2C785 /* ContactModel.swift in Sources */,
1A2D18F71F292D7200B2C785 /* MessageCellSent.swift in Sources */,
02E1A0251DDE4ABA00D75B59 /* String+Bool.swift in Sources */,
04399AAC1D1C304300E99CD9 /* AccountAdapter.mm in Sources */,
1AABA7461F0FE9C000739605 /* UIColor+Ring.swift in Sources */,
1A5DC0201F355DCF0075E8EF /* ContactsService.swift in Sources */,
......@@ -1313,6 +1315,7 @@
1A2041911F1FD46300C08435 /* DesignableView.swift in Sources */,
1A3D28A91F0EBF0200B524EE /* UIView+Ring.swift in Sources */,
1A2041881F1EA1EA00C08435 /* CreateAccountViewModel.swift in Sources */,
62E55B6D1F758E6F00D3FEF4 /* String+Helpers.swift in Sources */,
1ABE07D21F0D8FE800D36361 /* Images.swift in Sources */,
0273C3081E0C68BF00CF00BA /* DesignableButton.swift in Sources */,
1A5DC0321F3566140075E8EF /* ConversationSection.swift in Sources */,
......@@ -1333,6 +1336,7 @@
1A2D18EB1F29197100B2C785 /* MessageViewModel.swift in Sources */,
02B22DFF1DF755DB000358C9 /* AccountsService.swift in Sources */,
1A5DC0421F3567DF0075E8EF /* ContactRequestsCoordinator.swift in Sources */,
62E55B6F1F793ADE00D3FEF4 /* AvatarsColors.swift in Sources */,
1A5DC0401F35678D0075E8EF /* ContactRequestsViewModel.swift in Sources */,
56BBC9A21ED714DF00CDAF8B /* MessagesAdapterDelegate.swift in Sources */,
1A5DC0301F3565AE0075E8EF /* SmartlistViewController.swift in Sources */,
......
......@@ -33,3 +33,5 @@
#import "Chameleon/Chameleon.h"
#import "ContactsAdapter.h"
#import "PresenceAdapter.h"
#import <CommonCrypto/CommonCrypto.h>
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
import Foundation
// Colors from material.io
let avatarColors = [
UIColor(hexString: "#f44336"), // Red
UIColor(hexString: "#e91e63"), // Pink
UIColor(hexString: "#9c27b0"), // Purple
UIColor(hexString: "#673ab7"), // Deep Purple
UIColor(hexString: "#3f51b5"), // Indigo
UIColor(hexString: "#2196f3"), // Blue
UIColor(hexString: "#00bcd4"), // Cyan
UIColor(hexString: "#009688"), // Teal
UIColor(hexString: "#4caf50"), // Green
UIColor(hexString: "#8bc34a"), // Light Green
UIColor(hexString: "#9e9e9e"), // Grey
UIColor(hexString: "#cddc39"), // Lime
UIColor(hexString: "#ffc107"), // Amber
UIColor(hexString: "#ff5722"), // Deep Orange
UIColor(hexString: "#795548"), // Brown
UIColor(hexString: "#607d8b") // Blue Grey
];
let defaultAvatarColor = UIColor(hexString: "808080")
......@@ -2,6 +2,7 @@
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Edric Ladent-Milaret <edric.ladent-milaret@savoirfairelinux.com>
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -31,4 +32,20 @@ extension String {
return nil
}
}
func toMD5HexString() -> String {
let messageData = self.data(using:.utf8)!
var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
_ = digestData.withUnsafeMutableBytes { digestBytes in
messageData.withUnsafeBytes { messageBytes in
CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes)
}
}
return digestData.map { String(format: "%02hhx", $0) }.joined()
}
func prefixString() -> String {
return String(self.characters.prefix(1))
}
}
......@@ -24,6 +24,7 @@ import RxSwift
class ContactRequestCell: UITableViewCell, NibReusable {
@IBOutlet weak var fallbackAvatar: UILabel!
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var acceptButton: UIButton!
......
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16A323" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
......@@ -15,7 +15,7 @@
<rect key="frame" x="0.0" y="0.0" width="470" height="72"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KZx-bh-W5G" id="YU4-Oq-lYT">
<rect key="frame" x="0.0" y="0.0" width="470" height="71.5"/>
<rect key="frame" x="0.0" y="0.0" width="470" height="72"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_contact_picture" translatesAutoresizingMaskIntoConstraints="NO" id="xS9-Kd-lrg">
......@@ -104,6 +104,20 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="R" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wjc-Nn-INi" userLabel="Fallback Avatar">
<rect key="frame" x="16" y="16" width="40" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="20"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
<constraints>
<constraint firstItem="Pni-bm-rkr" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="8" id="0jS-6Q-w8N"/>
......@@ -126,6 +140,7 @@
<outlet property="acceptButton" destination="feR-9F-sZM" id="N3u-Ww-sE5"/>
<outlet property="banButton" destination="Pni-bm-rkr" id="v1p-37-zfP"/>
<outlet property="discardButton" destination="fWB-HR-tae" id="ZMu-NC-hE4"/>
<outlet property="fallbackAvatar" destination="Wjc-Nn-INi" id="vCB-ug-eic"/>
<outlet property="nameLabel" destination="Dla-OF-biH" id="tO5-og-I3P"/>
<outlet property="profileImageView" destination="xS9-Kd-lrg" id="Rxt-j1-fem"/>
</connections>
......
......@@ -31,6 +31,7 @@ class ContactRequestItem {
init(withContactRequest contactRequest: ContactRequestModel) {
self.contactRequest = contactRequest
self.userName.value = contactRequest.ringId
self.profileImageData = self.contactRequest.vCard?.imageData
}
}
......@@ -35,6 +35,8 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode
fileprivate let cellIdentifier = "ContactRequestCell"
fileprivate let log = SwiftyBeaver.self
fileprivate var backgroundColorObservable: Observable<UIColor>!
override func viewDidLoad() {
super.viewDidLoad()
......@@ -67,6 +69,31 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode
.bind(to: cell.nameLabel.rx.text)
.disposed(by: cell.disposeBag)
// Avatar placeholder initial
item.userName.asObservable()
.observeOn(MainScheduler.instance)
.map { value in value.prefixString().capitalized }
.bind(to: cell.fallbackAvatar.rx.text)
.disposed(by: cell.disposeBag)
// UIColor that observes "best Id" prefix
self.backgroundColorObservable = item.userName.asObservable()
.map { name in
let scanner = Scanner(string: name.toMD5HexString().prefixString())
var index: UInt64 = 0
if scanner.scanHexInt64(&index) {
return avatarColors[Int(index)]!
}
return defaultAvatarColor!
}
// Set placeholder avatar to backgroundColorObservable
self.backgroundColorObservable
.subscribe(onNext: { backgroundColor in
cell.fallbackAvatar.backgroundColor = backgroundColor
})
.disposed(by: cell.disposeBag)
if let imageData = item.profileImageData {
cell.profileImageView.image = UIImage(data: imageData)
}
......
......@@ -24,6 +24,7 @@ import Reusable
class ConversationCell: UITableViewCell, NibReusable {
@IBOutlet weak var fallbackAvatar: UILabel!
@IBOutlet weak var profileImage: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var newMessagesIndicator: UIView!
......@@ -33,12 +34,22 @@ class ConversationCell: UITableViewCell, NibReusable {
@IBOutlet weak var presenceIndicator: UIView!
override func setSelected(_ selected: Bool, animated: Bool) {
let presenceBGColor = self.presenceIndicator.backgroundColor
let fallbackAvatarBGColor = self.fallbackAvatar.backgroundColor
let newMessagesIndicatorBGColor = self.newMessagesIndicator.backgroundColor
super.setSelected(selected, animated: animated)
self.newMessagesIndicator.backgroundColor = UIColor.red
self.newMessagesIndicator.backgroundColor = newMessagesIndicatorBGColor
self.presenceIndicator.backgroundColor = presenceBGColor
self.fallbackAvatar.backgroundColor = fallbackAvatarBGColor
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
self.newMessagesIndicator.backgroundColor = UIColor.red
let presenceBGColor = self.presenceIndicator.backgroundColor
let fallbackAvatarBGColor = self.fallbackAvatar.backgroundColor
let newMessagesIndicatorBGColor = self.newMessagesIndicator.backgroundColor
super.setSelected(highlighted, animated: animated)
self.newMessagesIndicator.backgroundColor = newMessagesIndicatorBGColor
self.presenceIndicator.backgroundColor = presenceBGColor
self.fallbackAvatar.backgroundColor = fallbackAvatarBGColor
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F2073" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
......@@ -31,6 +31,19 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="R" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e0z-cM-gKq" userLabel="Fallback Avatar">
<rect key="frame" x="16" y="18" width="40" height="40"/>
<color key="backgroundColor" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="20"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Yesterday" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7Yv-cC-LKx">
<rect key="frame" x="281" y="31" width="61" height="15"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="12"/>
......@@ -93,6 +106,7 @@
<constraints>
<constraint firstItem="2fJ-Wf-1e0" firstAttribute="leading" secondItem="pFB-Jn-TNP" secondAttribute="trailing" constant="4" id="2NV-6m-dri"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="7Yv-cC-LKx" secondAttribute="bottom" constant="8" id="2O6-wC-voj"/>
<constraint firstItem="e0z-cM-gKq" firstAttribute="leading" secondItem="pFB-Jn-TNP" secondAttribute="leading" id="8PJ-pZ-MXg"/>
<constraint firstItem="eug-ak-r49" firstAttribute="leading" secondItem="pFB-Jn-TNP" secondAttribute="trailing" constant="4" id="9ah-Ed-RlY"/>
<constraint firstItem="pFB-Jn-TNP" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="9mO-5E-3lA"/>
<constraint firstItem="Fpi-20-ZYV" firstAttribute="bottom" secondItem="pFB-Jn-TNP" secondAttribute="bottom" id="BMe-Il-GoN"/>
......@@ -102,15 +116,19 @@
<constraint firstAttribute="trailing" secondItem="7Yv-cC-LKx" secondAttribute="trailing" constant="16" id="UOx-Og-IuZ"/>
<constraint firstItem="JTE-eF-Y5s" firstAttribute="top" secondItem="pFB-Jn-TNP" secondAttribute="top" id="W3A-IX-eXJ"/>
<constraint firstItem="7Yv-cC-LKx" firstAttribute="top" relation="greaterThanOrEqual" secondItem="H2p-sc-9uM" secondAttribute="top" constant="8" id="Wei-7X-4zv"/>
<constraint firstItem="e0z-cM-gKq" firstAttribute="bottom" secondItem="pFB-Jn-TNP" secondAttribute="bottom" id="ZEj-AJ-OZO"/>
<constraint firstItem="e0z-cM-gKq" firstAttribute="trailing" secondItem="JTE-eF-Y5s" secondAttribute="trailing" id="fyt-Cw-MG2"/>
<constraint firstItem="eug-ak-r49" firstAttribute="trailing" secondItem="2fJ-Wf-1e0" secondAttribute="trailing" id="mdZ-Uh-312"/>
<constraint firstItem="2fJ-Wf-1e0" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="8" id="omS-kb-QbN"/>
<constraint firstAttribute="bottom" secondItem="eug-ak-r49" secondAttribute="bottom" constant="8" id="rzH-w5-tpt"/>
<constraint firstItem="eug-ak-r49" firstAttribute="top" secondItem="2fJ-Wf-1e0" secondAttribute="bottom" constant="4" id="se0-Ur-K7G"/>
<constraint firstItem="pFB-Jn-TNP" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="16" id="suq-ak-BYg"/>
<constraint firstItem="7Yv-cC-LKx" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="xVO-gP-WdP"/>
<constraint firstItem="e0z-cM-gKq" firstAttribute="top" secondItem="JTE-eF-Y5s" secondAttribute="top" id="xfx-HF-Lm0"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="fallbackAvatar" destination="e0z-cM-gKq" id="fHH-qP-bx3"/>
<outlet property="lastMessageDateLabel" destination="7Yv-cC-LKx" id="pFf-hW-zD8"/>
<outlet property="lastMessagePreviewLabel" destination="eug-ak-r49" id="3jj-Lx-jbU"/>
<outlet property="nameLabel" destination="2fJ-Wf-1e0" id="0Mb-yC-vh6"/>
......
......@@ -23,6 +23,7 @@ import RxSwift
import RxDataSources
import RxCocoa
import Reusable
import SwiftyBeaver
//Constants
fileprivate struct SmartlistConstants {
......@@ -34,6 +35,8 @@ fileprivate struct SmartlistConstants {
class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased {
private let log = SwiftyBeaver.self
// MARK: outlets
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var conversationsTableView: UITableView!
......@@ -46,6 +49,8 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
var viewModel: SmartlistViewModel!
fileprivate let disposeBag = DisposeBag()
fileprivate var backgroundColorObservable: Observable<UIColor>!
// MARK: functions
override func viewDidLoad() {
super.viewDidLoad()
......@@ -122,6 +127,31 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
.bind(to: cell.nameLabel.rx.text)
.disposed(by: self.disposeBag)
// Avatar placeholder initial
item.userName.asObservable()
.observeOn(MainScheduler.instance)
.map { value in value.prefixString().capitalized }
.bind(to: cell.fallbackAvatar.rx.text)
.disposed(by: self.disposeBag)
// UIColor that observes "best Id" prefix
self.backgroundColorObservable = item.userName.asObservable()
.map { name in
let scanner = Scanner(string: name.toMD5HexString().prefixString())
var index: UInt64 = 0
if scanner.scanHexInt64(&index) {
return avatarColors[Int(index)]!
}
return defaultAvatarColor!
}
// Set placeholder avatar to backgroundColorObservable
self.backgroundColorObservable
.subscribe(onNext: { backgroundColor in
cell.fallbackAvatar.backgroundColor = backgroundColor
})
.disposed(by: self.disposeBag)
cell.newMessagesLabel.text = item.unreadMessages
cell.lastMessageDateLabel.text = item.lastMessageReceivedDate
cell.newMessagesIndicator.isHidden = item.hideNewMessagesLabel
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment