Skip to content

Commit

Permalink
Merge pull request #1115 from OrkhanAlikhanov/theme
Browse files Browse the repository at this point in the history
Introducing Theming to Material
  • Loading branch information
DanielDahan authored Oct 16, 2018
2 parents edab490 + 5ee47a0 commit 77a779d
Show file tree
Hide file tree
Showing 22 changed files with 647 additions and 83 deletions.
12 changes: 12 additions & 0 deletions Material.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
96E3C39A1D3A1CC20086A024 /* ErrorTextField.swift in Headers */ = {isa = PBXBuildFile; fileRef = 961F18E71CD93E3E008927C5 /* ErrorTextField.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96E3C39C1D3A1CC20086A024 /* Offset.swift in Headers */ = {isa = PBXBuildFile; fileRef = 968C99461D377849000074FF /* Offset.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96F1A5531F24F17A001D8CAF /* TabsController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96E09DC71F2287E50000B121 /* TabsController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9D00EBB4216675FB00DBCD69 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D00EBB3216675FB00DBCD69 /* Theme.swift */; };
9D054A6520D175AC00D0528D /* Material+UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D054A6320D175AC00D0528D /* Material+UIButton.swift */; };
9D054A6620D175AC00D0528D /* Material+UILabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D054A6420D175AC00D0528D /* Material+UILabel.swift */; };
9D39A81B20FE8ED100BA8FA1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D39A81A20FE8ED100BA8FA1 /* ViewController.swift */; };
Expand Down Expand Up @@ -292,6 +293,7 @@
96E09DC71F2287E50000B121 /* TabsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabsController.swift; sourceTree = "<group>"; };
96E3C3931D397AE90086A024 /* Material+UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+UIView.swift"; sourceTree = "<group>"; };
96F1DC871D654FDF0025F925 /* Material+CALayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+CALayer.swift"; sourceTree = "<group>"; };
9D00EBB3216675FB00DBCD69 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
9D054A6320D175AC00D0528D /* Material+UIButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+UIButton.swift"; sourceTree = "<group>"; };
9D054A6420D175AC00D0528D /* Material+UILabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+UILabel.swift"; sourceTree = "<group>"; };
9D39A81A20FE8ED100BA8FA1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -567,6 +569,7 @@
963FBF011D6696AB008F8512 /* Tab */,
966ECF2B1CF4C21B00BB0BDF /* Table */,
96090B031D9D709E00709CA6 /* Text */,
9D00EBB2216675A800DBCD69 /* Theme */,
963FBF001D66964F008F8512 /* Toolbar */,
9626CA951DAB5370003E2611 /* Transition */,
96BCB8061CB40FD000C806FE /* Type */,
Expand Down Expand Up @@ -760,6 +763,14 @@
name = Animation;
sourceTree = "<group>";
};
9D00EBB2216675A800DBCD69 /* Theme */ = {
isa = PBXGroup;
children = (
9D00EBB3216675FB00DBCD69 /* Theme.swift */,
);
name = Theme;
sourceTree = "<group>";
};
9DE84D6E1FF0250E00586C8B /* ButtonGroup */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1002,6 +1013,7 @@
966C17731F0439F600D3E83C /* Material+MotionAnimation.swift in Sources */,
965E80E51DD4C53300D61E4B /* PulseAnimation.swift in Sources */,
9DE84D721FF0252600586C8B /* RadioButtonGroup.swift in Sources */,
9D00EBB4216675FB00DBCD69 /* Theme.swift in Sources */,
965E80FE1DD4D59500D61E4B /* ToolbarController.swift in Sources */,
96328B971E05C0BB009A4C90 /* TableView.swift in Sources */,
965E80F81DD4D59500D61E4B /* ImageCard.swift in Sources */,
Expand Down
42 changes: 29 additions & 13 deletions Sources/iOS/BaseIconLayerButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ open class BaseIconLayerButton: Button {
open override var isSelected: Bool {
didSet {
iconLayer.setSelected(isSelected, animated: false)
updatePulseColor()
}
}

Expand Down Expand Up @@ -84,6 +85,7 @@ open class BaseIconLayerButton: Button {
open override func prepare() {
super.prepare()
layer.addSublayer(iconLayer)
iconLayer.prepare()
contentHorizontalAlignment = .left // default was .center
reloadImage()
}
Expand Down Expand Up @@ -122,7 +124,7 @@ open class BaseIconLayerButton: Button {
///
/// This property affects `intrinsicContentSize` and `sizeThatFits(_:)`
/// Use `iconEdgeInsets` to set margins.
open var iconSize: CGFloat = 16 {
open var iconSize: CGFloat = 18 {
didSet {
reloadImage()
}
Expand All @@ -136,12 +138,24 @@ open class BaseIconLayerButton: Button {
///
/// You can use `iconSize` and this property, or `titleEdgeInsets` and `contentEdgeInsets` to position
/// the icon however you want.
/// For negative values, behavior is undefined. Default is `5.0` for all four margins
open var iconEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) {
/// For negative values, behavior is undefined. Default is `8.0` for all four margins
open var iconEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) {
didSet {
reloadImage()
}
}

open override func apply(theme: Theme) {
super.apply(theme: theme)

setIconColor(theme.secondary, for: .selected)
setIconColor(theme.onSurface.withAlphaComponent(0.38), for: .normal)
titleColor = theme.onSurface.withAlphaComponent(0.60)

selectedPulseColor = theme.secondary
normalPulseColor = theme.onSurface
updatePulseColor()
}


/// This might be considered as a hackish way, but it's just manipulation
Expand All @@ -159,6 +173,18 @@ open class BaseIconLayerButton: Button {
UIGraphicsEndImageContext()
self.image = image
}

/// Pulse color for selected state.
open var selectedPulseColor = Color.white

/// Pulse color for normal state.
open var normalPulseColor = Color.white
}

private extension BaseIconLayerButton {
func updatePulseColor() {
pulseColor = isSelected ? selectedPulseColor : normalPulseColor
}
}

// MARK: - BaseIconLayer
Expand All @@ -185,16 +211,6 @@ internal class BaseIconLayer: CALayer {
}
}

override init() {
super.init()
prepare()
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepare()
}

func prepare() {
normalColor = { normalColor }() // calling didSet
selectedColor = { selectedColor }() // calling didSet
Expand Down
17 changes: 16 additions & 1 deletion Sources/iOS/BottomNavigationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private class MaterialTabBar: UITabBar {
}
}

open class BottomNavigationController: UITabBarController {
open class BottomNavigationController: UITabBarController, Themeable {
/// A Boolean that controls if the swipe feature is enabled.
open var isSwipeEnabled = true {
didSet {
Expand Down Expand Up @@ -168,6 +168,21 @@ open class BottomNavigationController: UITabBarController {
prepareTabBar()
isSwipeEnabled = true
isMotionEnabled = true
applyCurrentTheme()
}

/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open func apply(theme: Theme) {
tabBar.tintColor = theme.secondary
tabBar.barTintColor = theme.background
tabBar.dividerColor = theme.onSurface.withAlphaComponent(0.12)

if #available(iOS 10.0, *) {
tabBar.unselectedItemTintColor = theme.onSurface.withAlphaComponent(0.54)
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions Sources/iOS/Button.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import UIKit
import Motion

open class Button: UIButton, Pulseable, PulseableLayer {
open class Button: UIButton, Pulseable, PulseableLayer, Themeable {
/**
A CAShapeLayer used to manage elements that would be affected by
the clipToBounds property of the backing layer. For example, this
Expand Down Expand Up @@ -195,8 +195,8 @@ open class Button: UIButton, Pulseable, PulseableLayer {
*/
public init(image: UIImage?, tintColor: UIColor = Color.blue.base) {
super.init(frame: .zero)
prepare(with: image, tintColor: tintColor)
prepare()
prepare(with: image, tintColor: tintColor)
}

/**
Expand All @@ -206,8 +206,8 @@ open class Button: UIButton, Pulseable, PulseableLayer {
*/
public init(title: String?, titleColor: UIColor = Color.blue.base) {
super.init(frame: .zero)
prepare(with: title, titleColor: titleColor)
prepare()
prepare(with: title, titleColor: titleColor)
}

open override func layoutSubviews() {
Expand Down Expand Up @@ -281,7 +281,14 @@ open class Button: UIButton, Pulseable, PulseableLayer {
contentScaleFactor = Screen.scale
prepareVisualLayer()
preparePulse()
applyCurrentTheme()
}

/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open func apply(theme: Theme) { }
}

extension Button {
Expand Down
7 changes: 7 additions & 0 deletions Sources/iOS/CheckButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ open class CheckButton: BaseIconLayerButton {
guard !isAnimating else { return }
setSelected(!isSelected, animated: true)
}

open override func apply(theme: Theme) {
super.apply(theme: theme)

checkmarkColor = theme.onSecondary
}
}

internal class CheckBoxLayer: BaseIconLayer {
Expand Down Expand Up @@ -86,6 +92,7 @@ internal class CheckBoxLayer: BaseIconLayer {
if isSelected {
borderLayer.borderWidth = borderLayerNormalBorderWidth
} else {
borderLayer.borderWidth = 0
borderLayer.backgroundColor = (isEnabled ? normalColor : disabledColor).cgColor
checkMarkLeftLayer.strokeEnd = 1
checkMarkRightLayer.strokeEnd = 1
Expand Down
29 changes: 19 additions & 10 deletions Sources/iOS/Editor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public enum EditorPlaceholderAnimation {
case hidden
}

open class Editor: View {
open class Editor: View, Themeable {
/// Reference to textView.
public let textView = TextView()

Expand Down Expand Up @@ -173,11 +173,14 @@ open class Editor: View {

open override func prepare() {
super.prepare()
backgroundColor = nil
prepareDivider()
prepareTextView()
preparePlaceholderLabel()
prepareDetailLabel()
prepareNotificationHandlers()

applyCurrentTheme()
}

open override func layoutSubviews() {
Expand All @@ -187,6 +190,21 @@ open class Editor: View {
layoutBottomLabel(label: detailLabel, verticalOffset: detailVerticalOffset)
}

/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open func apply(theme: Theme) {
placeholderActiveColor = theme.secondary
placeholderNormalColor = theme.onSurface.withAlphaComponent(0.38)

dividerActiveColor = theme.secondary
dividerNormalColor = theme.onSurface.withAlphaComponent(0.12)

detailColor = theme.onSurface.withAlphaComponent(0.38)
textView.tintColor = theme.secondary
}

@discardableResult
open override func becomeFirstResponder() -> Bool {
return textView.becomeFirstResponder()
Expand All @@ -196,15 +214,6 @@ open class Editor: View {
open override func resignFirstResponder() -> Bool {
return textView.resignFirstResponder()
}

open override var inputAccessoryView: UIView? {
get {
return textView.inputAccessoryView
}
set(value) {
textView.inputAccessoryView = value
}
}
}


Expand Down
6 changes: 6 additions & 0 deletions Sources/iOS/ErrorTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,10 @@ open class ErrorTextField: TextField {
super.layoutSubviews()
layoutBottomLabel(label: errorLabel, verticalOffset: errorVerticalOffset)
}

open override func apply(theme: Theme) {
super.apply(theme: theme)

errorColor = theme.error
}
}
10 changes: 9 additions & 1 deletion Sources/iOS/FABButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ open class FABButton: Button {
depthPreset = .depth1
shapePreset = .circle
pulseAnimation = .centerWithBacking
backgroundColor = .white
}

open override func apply(theme: Theme) {
super.apply(theme: theme)

backgroundColor = theme.secondary
titleColor = theme.onSecondary
tintColor = theme.onSecondary
pulseColor = theme.onSecondary
}
}
9 changes: 9 additions & 0 deletions Sources/iOS/FlatButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ open class FlatButton: Button {
super.prepare()
cornerRadiusPreset = .cornerRadius1
}

open override func apply(theme: Theme) {
super.apply(theme: theme)

backgroundColor = .clear
titleColor = theme.secondary
tintColor = theme.secondary
pulseColor = theme.secondary
}
}
24 changes: 24 additions & 0 deletions Sources/iOS/IconButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,33 @@

import UIKit

public enum IconButtonThemingStyle {
/// Theming when background content is in background color.
case onBackground

/// Theming when background content is in primary color.
case onPrimary
}

open class IconButton: Button {
/// A reference to IconButtonThemingStyle.
open var themingStyle = IconButtonThemingStyle.onBackground

open override func prepare() {
super.prepare()
pulseAnimation = .center
}

open override func apply(theme: Theme) {
super.apply(theme: theme)

switch themingStyle {
case .onBackground:
tintColor = theme.secondary
pulseColor = theme.secondary
case .onPrimary:
tintColor = theme.onPrimary
pulseColor = theme.onPrimary
}
}
}
Loading

0 comments on commit 77a779d

Please sign in to comment.