Commit c572de59 authored by Andreas Traczyk's avatar Andreas Traczyk Committed by Kateryna Kostiuk

avatars: add fallback avatar image

- Draws a generic person overlay in the case of a ringId being the
  only available name.

- Sets the conversation's username to the contact's ringId at
  initialization, if no registered name is available.

- Sets the presence at conversation initialization.

Change-Id: I1874b57719398acd6aa096b645f540ce3a528cf0
Reviewed-by: Kateryna Kostiuk's avatarKateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
parent be425afc
......@@ -52,6 +52,7 @@ enum Asset {
static let contactRequestIcon = ImageAsset(name: "contact_request_icon")
static let conversationIcon = ImageAsset(name: "conversation_icon")
static let device = ImageAsset(name: "device")
static let fallbackAvatar = ImageAsset(name: "fallback_avatar")
static let icContactPicture = ImageAsset(name: "ic_contact_picture")
static let logoRingBeta2Blanc = ImageAsset(name: "logo-ring-beta2-blanc")
static let settingsIcon = ImageAsset(name: "settings_icon")
......@@ -66,6 +67,7 @@ enum Asset {
contactRequestIcon,
conversationIcon,
device,
fallbackAvatar,
icContactPicture,
logoRingBeta2Blanc,
settingsIcon,
......
......@@ -26,6 +26,7 @@ class ContactRequestCell: UITableViewCell, NibReusable {
@IBOutlet weak var fallbackAvatar: UILabel!
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var fallbackAvatarImage: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var acceptButton: UIButton!
@IBOutlet weak var discardButton: UIButton!
......
......@@ -32,6 +32,13 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="fallback_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="B6v-9R-dRD" userLabel="Fallback image">
<rect key="frame" x="16" y="16" width="40" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="3ok-c3-kW9"/>
<constraint firstAttribute="width" constant="40" id="PkF-FM-Zff"/>
</constraints>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="xS9-Kd-lrg">
<rect key="frame" x="16" y="16" width="40" height="40"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
......@@ -121,6 +128,7 @@
<constraints>
<constraint firstItem="Pni-bm-rkr" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="4" id="0jS-6Q-w8N"/>
<constraint firstItem="xS9-Kd-lrg" firstAttribute="centerY" secondItem="YU4-Oq-lYT" secondAttribute="centerY" id="DPx-jS-V0h"/>
<constraint firstItem="B6v-9R-dRD" firstAttribute="leading" secondItem="xS9-Kd-lrg" secondAttribute="leading" id="Dcd-fF-cHv"/>
<constraint firstItem="feR-9F-sZM" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="4" id="Gba-vQ-Ebp"/>
<constraint firstAttribute="bottom" secondItem="Pni-bm-rkr" secondAttribute="bottom" constant="8" id="KNE-9A-qWk"/>
<constraint firstItem="fWB-HR-tae" firstAttribute="top" secondItem="Dla-OF-biH" secondAttribute="bottom" constant="4" id="QMX-zx-zpZ"/>
......@@ -130,6 +138,7 @@
<constraint firstItem="Dla-OF-biH" firstAttribute="top" secondItem="YU4-Oq-lYT" secondAttribute="top" constant="8" id="hqf-Iv-xvb"/>
<constraint firstItem="fWB-HR-tae" firstAttribute="leading" secondItem="feR-9F-sZM" secondAttribute="trailing" constant="4" id="lfX-2s-AsZ"/>
<constraint firstItem="xS9-Kd-lrg" firstAttribute="leading" secondItem="YU4-Oq-lYT" secondAttribute="leading" constant="16" id="ogz-Qb-1Pz"/>
<constraint firstItem="B6v-9R-dRD" firstAttribute="top" secondItem="xS9-Kd-lrg" secondAttribute="top" id="sCh-oV-bKL"/>
<constraint firstAttribute="trailing" secondItem="Pni-bm-rkr" secondAttribute="trailing" constant="8" id="sDu-vC-6gU"/>
<constraint firstAttribute="trailing" secondItem="Dla-OF-biH" secondAttribute="trailing" constant="8" id="wFU-JT-uD3"/>
<constraint firstItem="Dla-OF-biH" firstAttribute="leading" secondItem="xS9-Kd-lrg" secondAttribute="trailing" constant="8" id="zIp-sT-nb3"/>
......@@ -140,10 +149,14 @@
<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="fallbackAvatarImage" destination="B6v-9R-dRD" id="XV9-ww-vFG"/>
<outlet property="nameLabel" destination="Dla-OF-biH" id="tO5-og-I3P"/>
<outlet property="profileImageView" destination="xS9-Kd-lrg" id="Rxt-j1-fem"/>
</connections>
<point key="canvasLocation" x="177" y="-50"/>
</tableViewCell>
</objects>
<resources>
<image name="fallback_avatar" width="82" height="82"/>
</resources>
</document>
......@@ -75,6 +75,7 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode
// Avatar placeholder initial
cell.fallbackAvatar.text = nil
cell.fallbackAvatarImage.isHidden = true
let name = item.userName.value
let scanner = Scanner(string: name.toMD5HexString().prefixString())
var index: UInt64 = 0
......@@ -83,6 +84,8 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode
cell.fallbackAvatar.backgroundColor = avatarColors[Int(index)]
if item.contactRequest.ringId != name {
cell.fallbackAvatar.text = name.prefixString().capitalized
} else {
cell.fallbackAvatarImage.isHidden = false
}
}
......@@ -95,6 +98,12 @@ class ContactRequestsViewController: UIViewController, StoryboardBased, ViewMode
.bind(to: cell.fallbackAvatar.rx.text)
.disposed(by: cell.disposeBag)
item.userName.asObservable()
.observeOn(MainScheduler.instance)
.map { [weak item] userName in userName != item?.contactRequest.ringId }
.bind(to: cell.fallbackAvatarImage.rx.isHidden)
.disposed(by: cell.disposeBag)
// UIColor that observes "best Id" prefix
self.backgroundColorObservable = item.userName.asObservable()
.observeOn(MainScheduler.instance)
......
......@@ -38,6 +38,7 @@ class MessageCell: UITableViewCell, NibReusable {
@IBOutlet weak var failedStatusLabel: UILabel!
@IBOutlet weak var profileImage: UIImageView!
@IBOutlet weak var fallbackAvatar: UILabel!
@IBOutlet weak var fallbackAvatarImage: UIImageView!
var disposeBag = DisposeBag()
......
......@@ -48,6 +48,13 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="fallback_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="tOS-Tt-QFy" userLabel="Fallback image">
<rect key="frame" x="16" y="4" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="1UM-p9-Mmj"/>
<constraint firstAttribute="width" constant="32" id="BIh-38-mEs"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WBd-CS-7Qv" userLabel="Top Corner">
<rect key="frame" x="64" y="8" width="15" height="15"/>
<color key="backgroundColor" red="1" green="0.0" blue="1" alpha="1" colorSpace="calibratedRGB"/>
......@@ -123,12 +130,14 @@
<constraint firstItem="eza-Ni-w3g" firstAttribute="leading" secondItem="mhg-uK-iD9" secondAttribute="trailing" constant="16" id="Pdf-ru-PnO"/>
<constraint firstItem="zuX-zz-1Qq" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="16" id="QoG-Zs-Lv7"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="kZJ-Ay-LTR" secondAttribute="trailing" constant="64" id="TCY-7X-mFs"/>
<constraint firstItem="tOS-Tt-QFy" firstAttribute="leading" secondItem="F9a-6w-Efg" secondAttribute="leading" id="WwB-B4-ZBk"/>
<constraint firstItem="skH-sJ-Ip9" firstAttribute="trailing" secondItem="kZJ-Ay-LTR" secondAttribute="leading" constant="-16" id="YCa-xJ-gRb"/>
<constraint firstItem="zuX-zz-1Qq" firstAttribute="trailing" secondItem="mhg-uK-iD9" secondAttribute="leading" constant="-16" id="aUU-d6-Dse"/>
<constraint firstItem="F9a-6w-Efg" firstAttribute="leading" secondItem="skH-sJ-Ip9" secondAttribute="leading" id="fx8-vF-4od"/>
<constraint firstItem="mhg-uK-iD9" firstAttribute="centerX" secondItem="H2p-sc-9uM" secondAttribute="centerX" id="gD0-yo-bga"/>
<constraint firstItem="kZJ-Ay-LTR" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="8" id="jhd-A8-c1o"/>
<constraint firstItem="kZJ-Ay-LTR" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="64" id="nWe-5k-Qpn"/>
<constraint firstItem="tOS-Tt-QFy" firstAttribute="top" secondItem="F9a-6w-Efg" secondAttribute="top" id="uEa-kN-oWY"/>
<constraint firstItem="eza-Ni-w3g" firstAttribute="centerY" secondItem="mhg-uK-iD9" secondAttribute="centerY" id="vhB-Uv-04a"/>
<constraint firstItem="F9a-6w-Efg" firstAttribute="bottom" secondItem="skH-sJ-Ip9" secondAttribute="bottom" id="w03-vx-kON"/>
<constraint firstItem="zuX-zz-1Qq" firstAttribute="centerY" secondItem="mhg-uK-iD9" secondAttribute="centerY" id="xFW-jt-00h"/>
......@@ -142,6 +151,7 @@
<outlet property="bubbleBottomConstraint" destination="1QQ-bu-6Bl" id="a4F-pf-cXL"/>
<outlet property="bubbleTopConstraint" destination="jhd-A8-c1o" id="40k-2d-6rW"/>
<outlet property="fallbackAvatar" destination="F9a-6w-Efg" id="JGo-mt-PVe"/>
<outlet property="fallbackAvatarImage" destination="tOS-Tt-QFy" id="Vts-Qp-g7I"/>
<outlet property="leftDivider" destination="zuX-zz-1Qq" id="9Jc-cV-VTA"/>
<outlet property="messageLabel" destination="lyR-7c-S2k" id="hd3-pz-Pwh"/>
<outlet property="profileImage" destination="skH-sJ-Ip9" id="pM2-t7-YhV"/>
......@@ -152,4 +162,7 @@
<point key="canvasLocation" x="-411" y="-132.5"/>
</tableViewCell>
</objects>
<resources>
<image name="fallback_avatar" width="82" height="82"/>
</resources>
</document>
......@@ -446,6 +446,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate, Storybo
// Set placeholder avatar
fallbackAvatar.text = nil
cell.fallbackAvatarImage.isHidden = true
let name = viewModel.userName.value
let scanner = Scanner(string: name.toMD5HexString().prefixString())
var index: UInt64 = 0
......@@ -454,6 +455,8 @@ class ConversationViewController: UIViewController, UITextFieldDelegate, Storybo
fallbackAvatar.backgroundColor = avatarColors[Int(index)]
if viewModel.conversation.value.recipientRingId != name {
fallbackAvatar.text = name.prefixString().capitalized
} else {
cell.fallbackAvatarImage.isHidden = true
}
}
......@@ -474,6 +477,12 @@ class ConversationViewController: UIViewController, UITextFieldDelegate, Storybo
.bind(to: fallbackAvatar.rx.text)
.disposed(by: cell.disposeBag)
viewModel.userName.asObservable()
.observeOn(MainScheduler.instance)
.map { [weak self] userName in userName != self?.viewModel.conversation.value.recipientRingId }
.bind(to: cell.fallbackAvatarImage.rx.isHidden)
.disposed(by: cell.disposeBag)
// Set image if any
cell.profileImage?.image = nil
if let imageData = viewModel.profileImageData {
......
......@@ -106,6 +106,12 @@ class ConversationViewModel: ViewModel {
}).disposed(by: self.disposeBag)
// subscribe to presence updates for the conversation's associated contact
if let contactPresence = self.presenceService.contactPresence[contactRingId] {
self.contactPresence.value = contactPresence
} else {
self.log.warning("Contact presence unkown for: \(contactRingId)")
self.contactPresence.value = false
}
self.presenceService
.sharedResponseStream
.filter({ presenceUpdateEvent in
......@@ -114,7 +120,7 @@ class ConversationViewModel: ViewModel {
})
.subscribe(onNext: { [unowned self] presenceUpdateEvent in
if let uri: String = presenceUpdateEvent.getEventInput(.uri) {
self.contactPresence.onNext(self.presenceService.contactPresence[uri]!)
self.contactPresence.value = self.presenceService.contactPresence[uri]!
}
})
.disposed(by: disposeBag)
......@@ -122,7 +128,7 @@ class ConversationViewModel: ViewModel {
if let contactUserName = contact?.userName {
self.userName.value = contactUserName
} else {
self.userName.value = contactRingId
// Return an observer for the username lookup
self.nameService.usernameLookupStatus
.filter({ lookupNameResponse in
......@@ -158,7 +164,7 @@ class ConversationViewModel: ViewModel {
var inviteButtonIsAvailable = BehaviorSubject(value: true)
var contactPresence = BehaviorSubject(value: false)
var contactPresence = Variable<Bool>(false)
var unreadMessages: String {
return self.unreadMessagesCount.description
......
......@@ -26,6 +26,7 @@ class ConversationCell: UITableViewCell, NibReusable {
@IBOutlet weak var fallbackAvatar: UILabel!
@IBOutlet weak var profileImage: UIImageView!
@IBOutlet weak var fallbackAvatarImage: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var newMessagesIndicator: UIView!
@IBOutlet weak var newMessagesLabel: UILabel!
......
......@@ -44,6 +44,13 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="fallback_avatar" translatesAutoresizingMaskIntoConstraints="NO" id="Rg3-gP-VHQ" userLabel="Fallback image">
<rect key="frame" x="16" y="18" width="40" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="NNq-lB-xLS"/>
<constraint firstAttribute="width" constant="40" id="fdG-Ph-C6j"/>
</constraints>
</imageView>
<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"/>
......@@ -120,10 +127,12 @@
<constraint firstItem="JTE-eF-Y5s" firstAttribute="trailing" secondItem="pFB-Jn-TNP" secondAttribute="trailing" id="MgK-cd-QXM"/>
<constraint firstItem="Fpi-20-ZYV" firstAttribute="trailing" secondItem="pFB-Jn-TNP" secondAttribute="trailing" id="Oav-3c-X7k"/>
<constraint firstAttribute="trailing" secondItem="7Yv-cC-LKx" secondAttribute="trailing" constant="16" id="UOx-Og-IuZ"/>
<constraint firstItem="Rg3-gP-VHQ" firstAttribute="leading" secondItem="e0z-cM-gKq" secondAttribute="leading" id="UVw-aO-f5u"/>
<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="Rg3-gP-VHQ" firstAttribute="top" secondItem="e0z-cM-gKq" secondAttribute="top" id="j2s-YP-du8"/>
<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"/>
......@@ -135,6 +144,7 @@
</tableViewCellContentView>
<connections>
<outlet property="fallbackAvatar" destination="e0z-cM-gKq" id="fHH-qP-bx3"/>
<outlet property="fallbackAvatarImage" destination="Rg3-gP-VHQ" id="Dk8-rq-MdX"/>
<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"/>
......@@ -146,4 +156,7 @@
<point key="canvasLocation" x="70" y="-92"/>
</tableViewCell>
</objects>
<resources>
<image name="fallback_avatar" width="82" height="82"/>
</resources>
</document>
......@@ -153,6 +153,7 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
// Avatar placeholder initial
cell.fallbackAvatar.text = nil
cell.fallbackAvatarImage.isHidden = true
let name = item.userName.value
let scanner = Scanner(string: name.toMD5HexString().prefixString())
var index: UInt64 = 0
......@@ -161,6 +162,8 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
cell.fallbackAvatar.backgroundColor = avatarColors[Int(index)]
if item.conversation.value.recipientRingId != name {
cell.fallbackAvatar.text = name.prefixString().capitalized
} else {
cell.fallbackAvatarImage.isHidden = false
}
}
......@@ -173,6 +176,12 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
.bind(to: cell.fallbackAvatar.rx.text)
.disposed(by: cell.disposeBag)
item.userName.asObservable()
.observeOn(MainScheduler.instance)
.map { [weak item] userName in userName != item?.conversation.value.recipientRingId }
.bind(to: cell.fallbackAvatarImage.rx.isHidden)
.disposed(by: cell.disposeBag)
// UIColor that observes "best Id" prefix
self.backgroundColorObservable = item.userName.asObservable()
.observeOn(MainScheduler.instance)
......
{
"images" : [
{
"idiom" : "universal",
"filename" : "default_avatar_overlay.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
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