Commit cfe0eba3 authored by Thibault Wittemberg's avatar Thibault Wittemberg

ui: add theming basis

This commit adds Chameleon to theme the app and a custom
theming function to handle MessageBubbles

Change-Id: I58e4d2e30c9e81a444b3a22cef4429d64361426d
parent 799a4cad
......@@ -3,3 +3,4 @@ github "RxSwiftCommunity/RxDataSources" == 1.0.3
github "pkluz/PKHUD"
github "AliSoftware/Reusable" ~> 4.0
github "SwiftyBeaver/SwiftyBeaver"
github "ViccAlexander/Chameleon"
......@@ -3,5 +3,6 @@ github "ReactiveX/RxSwift" "3.5.0"
github "RxSwiftCommunity/RxDataSources" "1.0.4"
github "RxSwiftCommunity/RxRealm" "0.6.0"
github "SwiftyBeaver/SwiftyBeaver" "1.3.0"
github "ViccAlexander/Chameleon" "2.2.0"
github "pkluz/PKHUD" "4.2.3"
github "realm/realm-cocoa" "v2.8.3"
This diff is collapsed.
......@@ -23,6 +23,7 @@ import UIKit
import RealmSwift
import SwiftyBeaver
import RxSwift
import Chameleon
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
......@@ -47,6 +48,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
SystemAdapter().registerConfigurationHandler()
self.startDaemon()
Chameleon.setGlobalThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light)
Chameleon.setRingThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light)
self.loadAccounts()
return true
}
......
......@@ -30,3 +30,4 @@
#import "RegistrationResponse.h"
#import "NameRegistrationResponse.h"
#import "MessagesAdapter.h"
#import "Chameleon/Chameleon.h"
......@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "Chameleon/Chameleon-Swift.h"
#import "Ring-Swift.h"
#import "SystemAdapter.h"
......
......@@ -63,6 +63,8 @@ enum L10n {
enum Global {
/// Home
static let homeTabBarTitle = L10n.tr("global.homeTabBarTitle")
/// Me
static let meTabBarTitle = L10n.tr("global.meTabBarTitle")
/// Ok
static let ok = L10n.tr("global.ok")
}
......
......@@ -26,6 +26,7 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
let disposeBag = DisposeBag()
var viewModel: ConversationViewModel?
var messageViewModels: [MessageViewModel]?
var textFieldShouldEndEditing = false
var bottomOffset: CGFloat = 0
......@@ -92,20 +93,21 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
}
func setupTableView() {
self.tableView.dataSource = self
self.tableView.estimatedRowHeight = 50
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.separatorStyle = .none
//Register cell
self.tableView.register(cellType: MessageCell.self)
self.tableView.register(cellType: MessageCellSent.self)
self.tableView.register(cellType: MessageCellReceived.self)
//Bind the TableView to the ViewModel
self.viewModel?.messages
.bind(to: tableView.rx.items(cellIdentifier: "MessageCell",
cellType: MessageCell.self)) { _, messageViewModel, cell in
cell.messageLabel.text = messageViewModel.content
cell.bubblePosition = messageViewModel.bubblePosition()
}.disposed(by: disposeBag)
self.viewModel?.messages.subscribe(onNext: { [weak self] (messageViewModels) in
self?.messageViewModels = messageViewModels
self?.tableView.reloadData()
}).disposed(by: self.disposeBag)
//Scroll to bottom when reloaded
self.tableView.rx.methodInvoked(#selector(UITableView.reloadData)).subscribe(onNext: { _ in
......@@ -170,3 +172,28 @@ class ConversationViewController: UIViewController, UITextFieldDelegate {
}
}
extension ConversationViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.messageViewModels?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let messageViewModel = self.messageViewModels?[indexPath.row] {
if messageViewModel.bubblePosition() == .received {
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: MessageCellReceived.self)
cell.messageLabel.text = messageViewModel.content
return cell
}
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: MessageCellSent.self)
cell.messageLabel.text = messageViewModel.content
return cell
}
return tableView.dequeueReusableCell(for: indexPath, cellType: MessageCellSent.self)
}
}
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Thibault Wittemberg <thibault.wittemberg@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
import Chameleon
extension Chameleon {
static func setRingThemeUsingPrimaryColor (_ primaryColor: UIColor, withSecondaryColor secondaryColor: UIColor, andContentStyle contentStyle: UIContentStyle) {
var contentColor: UIColor
var secondaryContentColor: UIColor
switch contentStyle {
case .contrast:
contentColor = ContrastColorOf(primaryColor, returnFlat: false)
secondaryContentColor = ContrastColorOf(secondaryColor, returnFlat: false)
break
case .light:
contentColor = UIColor.white
secondaryContentColor = UIColor.white
break
case .dark:
contentColor = UIColor.flatBlackColorDark()
secondaryContentColor = UIColor.flatBlackColorDark()
break
}
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = UIColor.flatGray()
MessageBubble.appearance().tintColor = secondaryContentColor
MessageBubble.appearance().backgroundColor = secondaryColor
MessageBubble.appearance(whenContainedInInstancesOf: [MessageCellSent.self]).tintColor = contentColor
MessageBubble.appearance(whenContainedInInstancesOf: [MessageCellSent.self]).backgroundColor = primaryColor
UILabel.appearance(whenContainedInInstancesOf: [MessageBubble.self, MessageCellSent.self]).textColor = contentColor
MessageBubble.appearance(whenContainedInInstancesOf: [MessageCellReceived.self]).tintColor = secondaryContentColor
MessageBubble.appearance(whenContainedInInstancesOf: [MessageCellReceived.self]).backgroundColor = secondaryColor
UILabel.appearance(whenContainedInInstancesOf: [MessageBubble.self, MessageCellReceived.self]).textColor = secondaryContentColor
}
}
......@@ -23,9 +23,14 @@ import UIKit
extension UIColor {
static let ringMain = UIColor(colorLiteralRed: 10.0/255.0,
green: 116.0/255.0,
blue: 137.0/255.0,
static let ringMain = UIColor(colorLiteralRed: 58.0/255.0,
green: 192.0/255.0,
blue: 210.0/255.0,
alpha: 1.0)
static let ringSecondary = UIColor(colorLiteralRed: 0.0/255.0,
green: 76.0/255.0,
blue: 96.0/255.0,
alpha: 1.0)
}
......@@ -54,6 +54,6 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<false/>
</dict>
</plist>
......@@ -25,8 +25,6 @@ class MainTabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
UITabBarItem.appearance()
.setTitleTextAttributes( [NSForegroundColorAttributeName: UIColor.ringMain], for: .selected)
}
override func viewDidAppear(_ animated: Bool) {
......
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
*
* Author: Thibault Wittemberg <thibault.wittemberg@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
import UIKit
@IBDesignable
class MessageBubble: UIView {
// just to make the UIView+Ring extension IBDesignable
}
......@@ -21,50 +21,9 @@
import UIKit
import Reusable
enum BubblePosition {
case received
case sent
}
class MessageCell: UITableViewCell, NibReusable {
class MessageCellReceived: UITableViewCell, NibReusable {
@IBOutlet weak var bubble: UIView!
@IBOutlet weak var bubble: MessageBubble!
@IBOutlet weak var messageLabel: UILabel!
@IBOutlet weak var minimumLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var containerLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var minimumTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var containerTrailingConstraint: NSLayoutConstraint!
var bubblePosition = BubblePosition.received {
didSet {
if bubblePosition == .sent {
self.minimumTrailingConstraint.priority = 1
self.containerTrailingConstraint.priority = 999
self.containerLeadingConstraint.priority = 1
self.minimumLeadingConstraint.priority = 999
self.bubble.backgroundColor = UIColor.ringMain
self.messageLabel.textColor = UIColor.white
} else {
self.minimumLeadingConstraint.priority = 1
self.containerLeadingConstraint.priority = 999
self.containerTrailingConstraint.priority = 1
self.minimumTrailingConstraint.priority = 999
self.bubble.backgroundColor = UIColor.lightGray
self.messageLabel.textColor = UIColor.black
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.bubblePosition = .received
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
......@@ -11,14 +11,14 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" rowHeight="60" id="KGk-i7-Jjw" customClass="MessageCell" customModule="Ring" customModuleProvider="target">
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" rowHeight="60" id="KGk-i7-Jjw" customClass="MessageCellReceived" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="510" height="47"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="510" height="46.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kZJ-Ay-LTR">
<view clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kZJ-Ay-LTR" customClass="MessageBubble" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="16" y="8" width="152.5" height="30.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label Label Label Label " lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lyR-7c-S2k">
......@@ -37,8 +37,8 @@
<constraint firstItem="lyR-7c-S2k" firstAttribute="top" secondItem="kZJ-Ay-LTR" secondAttribute="top" constant="4" id="ycc-WI-Jk6"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="5"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="4"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
......@@ -54,11 +54,7 @@
</tableViewCellContentView>
<connections>
<outlet property="bubble" destination="kZJ-Ay-LTR" id="hdG-fG-L69"/>
<outlet property="containerLeadingConstraint" destination="nWe-5k-Qpn" id="Ahu-gW-4IY"/>
<outlet property="containerTrailingConstraint" destination="99Y-bR-Ioq" id="JJr-pE-UfA"/>
<outlet property="messageLabel" destination="lyR-7c-S2k" id="hd3-pz-Pwh"/>
<outlet property="minimumLeadingConstraint" destination="Eso-cy-OYs" id="jhV-mE-FMA"/>
<outlet property="minimumTrailingConstraint" destination="TCY-7X-mFs" id="xj3-4A-I9G"/>
</connections>
<point key="canvasLocation" x="-411" y="-132"/>
</tableViewCell>
......
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
*
* Author: Silbino Gonçalves Matado <silbino.gmatado@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 UIKit
import Reusable
class MessageCellSent: UITableViewCell, NibReusable {
@IBOutlet weak var bubble: MessageBubble!
@IBOutlet weak var messageLabel: UILabel!
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16E195" 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="12089"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" rowHeight="60" id="KGk-i7-Jjw" customClass="MessageCellSent" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="510" height="47"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="510" height="46.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="kZJ-Ay-LTR" customClass="MessageBubble" customModule="Ring" customModuleProvider="target">
<rect key="frame" x="341.5" y="8" width="152.5" height="30.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label Label Label Label " lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lyR-7c-S2k">
<rect key="frame" x="8" y="4" width="136.5" height="22.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="30" id="1Kj-UZ-gu7"/>
<constraint firstItem="lyR-7c-S2k" firstAttribute="leading" secondItem="kZJ-Ay-LTR" secondAttribute="leading" constant="8" id="8m5-sR-xnh"/>
<constraint firstAttribute="bottom" secondItem="lyR-7c-S2k" secondAttribute="bottom" constant="4" id="gwN-uX-PWd"/>
<constraint firstAttribute="trailing" secondItem="lyR-7c-S2k" secondAttribute="trailing" constant="8" id="uzV-kG-oGN"/>
<constraint firstItem="lyR-7c-S2k" firstAttribute="top" secondItem="kZJ-Ay-LTR" secondAttribute="top" constant="4" id="ycc-WI-Jk6"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
<real key="value" value="4"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="kZJ-Ay-LTR" secondAttribute="bottom" constant="8" id="1QQ-bu-6Bl"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="kZJ-Ay-LTR" secondAttribute="trailing" priority="1" constant="64" id="99Y-bR-Ioq"/>
<constraint firstItem="kZJ-Ay-LTR" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" priority="1" constant="16" id="Eso-cy-OYs"/>
<constraint firstAttribute="trailing" secondItem="kZJ-Ay-LTR" secondAttribute="trailing" constant="16" id="TCY-7X-mFs"/>
<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" relation="greaterThanOrEqual" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="64" id="nWe-5k-Qpn"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="bubble" destination="kZJ-Ay-LTR" id="hdG-fG-L69"/>
<outlet property="messageLabel" destination="lyR-7c-S2k" id="hd3-pz-Pwh"/>
</connections>
<point key="canvasLocation" x="-411" y="-132"/>
</tableViewCell>
</objects>
</document>
......@@ -20,6 +20,11 @@
import RxSwift
enum BubblePosition {
case received
case sent
}
class MessageViewModel {
fileprivate let accountService = AppDelegate.accountService
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
// Global
"global.homeTabBarTitle" = "Home";
"global.meTabBarTitle" = "Me";
"global.ok" = "Ok";
// Smartlist
......
......@@ -32,6 +32,9 @@ class MeViewController: UIViewController, UITableViewDelegate, UITableViewDataSo
override func viewDidLoad() {
super.viewDidLoad()
self.title = L10n.Global.meTabBarTitle.smartString
self.navigationItem.title = L10n.Global.meTabBarTitle.smartString
if !accountService.accounts.isEmpty {
// let acc = accountService.accounts[0]
// nameLabel.text = acc.displayName
......
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