Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
Material
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Dmitriy Stepanets
Material
Commits
77a779df
Unverified
Commit
77a779df
authored
Oct 16, 2018
by
Daniel Jonathan
Committed by
GitHub
Oct 16, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1115 from OrkhanAlikhanov/theme
Introducing Theming to Material
parents
edab4901
5ee47a0c
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
647 additions
and
83 deletions
+647
-83
Material.xcodeproj/project.pbxproj
+12
-0
Sources/iOS/BaseIconLayerButton.swift
+29
-13
Sources/iOS/BottomNavigationController.swift
+16
-1
Sources/iOS/Button.swift
+10
-3
Sources/iOS/CheckButton.swift
+7
-0
Sources/iOS/Editor.swift
+19
-10
Sources/iOS/ErrorTextField.swift
+6
-0
Sources/iOS/FABButton.swift
+9
-1
Sources/iOS/FlatButton.swift
+9
-0
Sources/iOS/IconButton.swift
+24
-0
Sources/iOS/Material+UIColor.swift
+63
-0
Sources/iOS/NavigationBar.swift
+27
-3
Sources/iOS/RaisedButton.swift
+9
-1
Sources/iOS/StatusBarController.swift
+6
-0
Sources/iOS/Switch.swift
+19
-45
Sources/iOS/TabBar.swift
+2
-0
Sources/iOS/TabsController.swift
+60
-1
Sources/iOS/TextField.swift
+20
-1
Sources/iOS/TextView.swift
+11
-1
Sources/iOS/Theme.swift
+229
-0
Sources/iOS/Toolbar.swift
+50
-1
Sources/iOS/ViewController.swift
+10
-2
No files found.
Material.xcodeproj/project.pbxproj
View file @
77a779df
...
@@ -170,6 +170,7 @@
...
@@ -170,6 +170,7 @@
96E3C39A1D3A1CC20086A024
/* ErrorTextField.swift in Headers */
=
{
isa
=
PBXBuildFile
;
fileRef
=
961F18E71CD93E3E008927C5
/* ErrorTextField.swift */
;
settings
=
{
ATTRIBUTES
=
(
Public
,
);
};
};
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
,
);
};
};
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
,
);
};
};
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 */
;
};
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 */
;
};
9D054A6620D175AC00D0528D
/* Material+UILabel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9D054A6420D175AC00D0528D
/* Material+UILabel.swift */
;
};
9D39A81B20FE8ED100BA8FA1
/* ViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9D39A81A20FE8ED100BA8FA1
/* ViewController.swift */
;
};
9D39A81B20FE8ED100BA8FA1
/* ViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
9D39A81A20FE8ED100BA8FA1
/* ViewController.swift */
;
};
...
@@ -292,6 +293,7 @@
...
@@ -292,6 +293,7 @@
96E09DC71F2287E50000B121
/* TabsController.swift */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
sourcecode.swift
;
path
=
TabsController.swift
;
sourceTree
=
"<group>"
;
};
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>"
;
};
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>"
;
};
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>"
;
};
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>"
;
};
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>"
;
};
9D39A81A20FE8ED100BA8FA1
/* ViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ViewController.swift
;
sourceTree
=
"<group>"
;
};
...
@@ -567,6 +569,7 @@
...
@@ -567,6 +569,7 @@
963FBF011D6696AB008F8512
/* Tab */
,
963FBF011D6696AB008F8512
/* Tab */
,
966ECF2B1CF4C21B00BB0BDF
/* Table */
,
966ECF2B1CF4C21B00BB0BDF
/* Table */
,
96090B031D9D709E00709CA6
/* Text */
,
96090B031D9D709E00709CA6
/* Text */
,
9D00EBB2216675A800DBCD69
/* Theme */
,
963FBF001D66964F008F8512
/* Toolbar */
,
963FBF001D66964F008F8512
/* Toolbar */
,
9626CA951DAB5370003E2611
/* Transition */
,
9626CA951DAB5370003E2611
/* Transition */
,
96BCB8061CB40FD000C806FE
/* Type */
,
96BCB8061CB40FD000C806FE
/* Type */
,
...
@@ -760,6 +763,14 @@
...
@@ -760,6 +763,14 @@
name
=
Animation
;
name
=
Animation
;
sourceTree
=
"<group>"
;
sourceTree
=
"<group>"
;
};
};
9D00EBB2216675A800DBCD69
/* Theme */
=
{
isa
=
PBXGroup
;
children
=
(
9D00EBB3216675FB00DBCD69
/* Theme.swift */
,
);
name
=
Theme
;
sourceTree
=
"<group>"
;
};
9DE84D6E1FF0250E00586C8B
/* ButtonGroup */
=
{
9DE84D6E1FF0250E00586C8B
/* ButtonGroup */
=
{
isa
=
PBXGroup
;
isa
=
PBXGroup
;
children
=
(
children
=
(
...
@@ -1002,6 +1013,7 @@
...
@@ -1002,6 +1013,7 @@
966C17731F0439F600D3E83C
/* Material+MotionAnimation.swift in Sources */
,
966C17731F0439F600D3E83C
/* Material+MotionAnimation.swift in Sources */
,
965E80E51DD4C53300D61E4B
/* PulseAnimation.swift in Sources */
,
965E80E51DD4C53300D61E4B
/* PulseAnimation.swift in Sources */
,
9DE84D721FF0252600586C8B
/* RadioButtonGroup.swift in Sources */
,
9DE84D721FF0252600586C8B
/* RadioButtonGroup.swift in Sources */
,
9D00EBB4216675FB00DBCD69
/* Theme.swift in Sources */
,
965E80FE1DD4D59500D61E4B
/* ToolbarController.swift in Sources */
,
965E80FE1DD4D59500D61E4B
/* ToolbarController.swift in Sources */
,
96328B971E05C0BB009A4C90
/* TableView.swift in Sources */
,
96328B971E05C0BB009A4C90
/* TableView.swift in Sources */
,
965E80F81DD4D59500D61E4B
/* ImageCard.swift in Sources */
,
965E80F81DD4D59500D61E4B
/* ImageCard.swift in Sources */
,
...
...
Sources/iOS/BaseIconLayerButton.swift
View file @
77a779df
...
@@ -20,6 +20,7 @@ open class BaseIconLayerButton: Button {
...
@@ -20,6 +20,7 @@ open class BaseIconLayerButton: Button {
open
override
var
isSelected
:
Bool
{
open
override
var
isSelected
:
Bool
{
didSet
{
didSet
{
iconLayer
.
setSelected
(
isSelected
,
animated
:
false
)
iconLayer
.
setSelected
(
isSelected
,
animated
:
false
)
updatePulseColor
()
}
}
}
}
...
@@ -84,6 +85,7 @@ open class BaseIconLayerButton: Button {
...
@@ -84,6 +85,7 @@ open class BaseIconLayerButton: Button {
open
override
func
prepare
()
{
open
override
func
prepare
()
{
super
.
prepare
()
super
.
prepare
()
layer
.
addSublayer
(
iconLayer
)
layer
.
addSublayer
(
iconLayer
)
iconLayer
.
prepare
()
contentHorizontalAlignment
=
.
left
// default was .center
contentHorizontalAlignment
=
.
left
// default was .center
reloadImage
()
reloadImage
()
}
}
...
@@ -122,7 +124,7 @@ open class BaseIconLayerButton: Button {
...
@@ -122,7 +124,7 @@ open class BaseIconLayerButton: Button {
///
///
/// This property affects `intrinsicContentSize` and `sizeThatFits(_:)`
/// This property affects `intrinsicContentSize` and `sizeThatFits(_:)`
/// Use `iconEdgeInsets` to set margins.
/// Use `iconEdgeInsets` to set margins.
open
var
iconSize
:
CGFloat
=
1
6
{
open
var
iconSize
:
CGFloat
=
1
8
{
didSet
{
didSet
{
reloadImage
()
reloadImage
()
}
}
...
@@ -136,12 +138,24 @@ open class BaseIconLayerButton: Button {
...
@@ -136,12 +138,24 @@ open class BaseIconLayerButton: Button {
///
///
/// You can use `iconSize` and this property, or `titleEdgeInsets` and `contentEdgeInsets` to position
/// You can use `iconSize` and this property, or `titleEdgeInsets` and `contentEdgeInsets` to position
/// the icon however you want.
/// the icon however you want.
/// For negative values, behavior is undefined. Default is `
5
.0` for all four margins
/// For negative values, behavior is undefined. Default is `
8
.0` for all four margins
open
var
iconEdgeInsets
=
UIEdgeInsets
(
top
:
5
,
left
:
5
,
bottom
:
5
,
right
:
5
)
{
open
var
iconEdgeInsets
=
UIEdgeInsets
(
top
:
8
,
left
:
8
,
bottom
:
8
,
right
:
8
)
{
didSet
{
didSet
{
reloadImage
()
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
/// This might be considered as a hackish way, but it's just manipulation
...
@@ -159,6 +173,18 @@ open class BaseIconLayerButton: Button {
...
@@ -159,6 +173,18 @@ open class BaseIconLayerButton: Button {
UIGraphicsEndImageContext
()
UIGraphicsEndImageContext
()
self
.
image
=
image
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
// MARK: - BaseIconLayer
...
@@ -185,16 +211,6 @@ internal class BaseIconLayer: CALayer {
...
@@ -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
()
{
func
prepare
()
{
normalColor
=
{
normalColor
}()
// calling didSet
normalColor
=
{
normalColor
}()
// calling didSet
selectedColor
=
{
selectedColor
}()
// calling didSet
selectedColor
=
{
selectedColor
}()
// calling didSet
...
...
Sources/iOS/BottomNavigationController.swift
View file @
77a779df
...
@@ -51,7 +51,7 @@ private class MaterialTabBar: UITabBar {
...
@@ -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.
/// A Boolean that controls if the swipe feature is enabled.
open
var
isSwipeEnabled
=
true
{
open
var
isSwipeEnabled
=
true
{
didSet
{
didSet
{
...
@@ -168,6 +168,21 @@ open class BottomNavigationController: UITabBarController {
...
@@ -168,6 +168,21 @@ open class BottomNavigationController: UITabBarController {
prepareTabBar
()
prepareTabBar
()
isSwipeEnabled
=
true
isSwipeEnabled
=
true
isMotionEnabled
=
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
)
}
}
}
}
}
...
...
Sources/iOS/Button.swift
View file @
77a779df
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
import
UIKit
import
UIKit
import
Motion
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
A CAShapeLayer used to manage elements that would be affected by
the clipToBounds property of the backing layer. For example, this
the clipToBounds property of the backing layer. For example, this
...
@@ -195,8 +195,8 @@ open class Button: UIButton, Pulseable, PulseableLayer {
...
@@ -195,8 +195,8 @@ open class Button: UIButton, Pulseable, PulseableLayer {
*/
*/
public
init
(
image
:
UIImage
?,
tintColor
:
UIColor
=
Color
.
blue
.
base
)
{
public
init
(
image
:
UIImage
?,
tintColor
:
UIColor
=
Color
.
blue
.
base
)
{
super
.
init
(
frame
:
.
zero
)
super
.
init
(
frame
:
.
zero
)
prepare
(
with
:
image
,
tintColor
:
tintColor
)
prepare
()
prepare
()
prepare
(
with
:
image
,
tintColor
:
tintColor
)
}
}
/**
/**
...
@@ -206,8 +206,8 @@ open class Button: UIButton, Pulseable, PulseableLayer {
...
@@ -206,8 +206,8 @@ open class Button: UIButton, Pulseable, PulseableLayer {
*/
*/
public
init
(
title
:
String
?,
titleColor
:
UIColor
=
Color
.
blue
.
base
)
{
public
init
(
title
:
String
?,
titleColor
:
UIColor
=
Color
.
blue
.
base
)
{
super
.
init
(
frame
:
.
zero
)
super
.
init
(
frame
:
.
zero
)
prepare
(
with
:
title
,
titleColor
:
titleColor
)
prepare
()
prepare
()
prepare
(
with
:
title
,
titleColor
:
titleColor
)
}
}
open
override
func
layoutSubviews
()
{
open
override
func
layoutSubviews
()
{
...
@@ -281,7 +281,14 @@ open class Button: UIButton, Pulseable, PulseableLayer {
...
@@ -281,7 +281,14 @@ open class Button: UIButton, Pulseable, PulseableLayer {
contentScaleFactor
=
Screen
.
scale
contentScaleFactor
=
Screen
.
scale
prepareVisualLayer
()
prepareVisualLayer
()
preparePulse
()
preparePulse
()
applyCurrentTheme
()
}
}
/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
}
}
}
extension
Button
{
extension
Button
{
...
...
Sources/iOS/CheckButton.swift
View file @
77a779df
...
@@ -31,6 +31,12 @@ open class CheckButton: BaseIconLayerButton {
...
@@ -31,6 +31,12 @@ open class CheckButton: BaseIconLayerButton {
guard
!
isAnimating
else
{
return
}
guard
!
isAnimating
else
{
return
}
setSelected
(
!
isSelected
,
animated
:
true
)
setSelected
(
!
isSelected
,
animated
:
true
)
}
}
open
override
func
apply
(
theme
:
Theme
)
{
super
.
apply
(
theme
:
theme
)
checkmarkColor
=
theme
.
onSecondary
}
}
}
internal
class
CheckBoxLayer
:
BaseIconLayer
{
internal
class
CheckBoxLayer
:
BaseIconLayer
{
...
@@ -86,6 +92,7 @@ internal class CheckBoxLayer: BaseIconLayer {
...
@@ -86,6 +92,7 @@ internal class CheckBoxLayer: BaseIconLayer {
if
isSelected
{
if
isSelected
{
borderLayer
.
borderWidth
=
borderLayerNormalBorderWidth
borderLayer
.
borderWidth
=
borderLayerNormalBorderWidth
}
else
{
}
else
{
borderLayer
.
borderWidth
=
0
borderLayer
.
backgroundColor
=
(
isEnabled
?
normalColor
:
disabledColor
)
.
cgColor
borderLayer
.
backgroundColor
=
(
isEnabled
?
normalColor
:
disabledColor
)
.
cgColor
checkMarkLeftLayer
.
strokeEnd
=
1
checkMarkLeftLayer
.
strokeEnd
=
1
checkMarkRightLayer
.
strokeEnd
=
1
checkMarkRightLayer
.
strokeEnd
=
1
...
...
Sources/iOS/Editor.swift
View file @
77a779df
...
@@ -35,7 +35,7 @@ public enum EditorPlaceholderAnimation {
...
@@ -35,7 +35,7 @@ public enum EditorPlaceholderAnimation {
case
hidden
case
hidden
}
}
open
class
Editor
:
View
{
open
class
Editor
:
View
,
Themeable
{
/// Reference to textView.
/// Reference to textView.
public
let
textView
=
TextView
()
public
let
textView
=
TextView
()
...
@@ -173,11 +173,14 @@ open class Editor: View {
...
@@ -173,11 +173,14 @@ open class Editor: View {
open
override
func
prepare
()
{
open
override
func
prepare
()
{
super
.
prepare
()
super
.
prepare
()
backgroundColor
=
nil
prepareDivider
()
prepareDivider
()
prepareTextView
()
prepareTextView
()
preparePlaceholderLabel
()
preparePlaceholderLabel
()
prepareDetailLabel
()
prepareDetailLabel
()
prepareNotificationHandlers
()
prepareNotificationHandlers
()
applyCurrentTheme
()
}
}
open
override
func
layoutSubviews
()
{
open
override
func
layoutSubviews
()
{
...
@@ -187,6 +190,21 @@ open class Editor: View {
...
@@ -187,6 +190,21 @@ open class Editor: View {
layoutBottomLabel
(
label
:
detailLabel
,
verticalOffset
:
detailVerticalOffset
)
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
@discardableResult
open
override
func
becomeFirstResponder
()
->
Bool
{
open
override
func
becomeFirstResponder
()
->
Bool
{
return
textView
.
becomeFirstResponder
()
return
textView
.
becomeFirstResponder
()
...
@@ -196,15 +214,6 @@ open class Editor: View {
...
@@ -196,15 +214,6 @@ open class Editor: View {
open
override
func
resignFirstResponder
()
->
Bool
{
open
override
func
resignFirstResponder
()
->
Bool
{
return
textView
.
resignFirstResponder
()
return
textView
.
resignFirstResponder
()
}
}
open
override
var
inputAccessoryView
:
UIView
?
{
get
{
return
textView
.
inputAccessoryView
}
set
(
value
)
{
textView
.
inputAccessoryView
=
value
}
}
}
}
...
...
Sources/iOS/ErrorTextField.swift
View file @
77a779df
...
@@ -93,4 +93,10 @@ open class ErrorTextField: TextField {
...
@@ -93,4 +93,10 @@ open class ErrorTextField: TextField {
super
.
layoutSubviews
()
super
.
layoutSubviews
()
layoutBottomLabel
(
label
:
errorLabel
,
verticalOffset
:
errorVerticalOffset
)
layoutBottomLabel
(
label
:
errorLabel
,
verticalOffset
:
errorVerticalOffset
)
}
}
open
override
func
apply
(
theme
:
Theme
)
{
super
.
apply
(
theme
:
theme
)
errorColor
=
theme
.
error
}
}
}
Sources/iOS/FABButton.swift
View file @
77a779df
...
@@ -36,6 +36,14 @@ open class FABButton: Button {
...
@@ -36,6 +36,14 @@ open class FABButton: Button {
depthPreset
=
.
depth1
depthPreset
=
.
depth1
shapePreset
=
.
circle
shapePreset
=
.
circle
pulseAnimation
=
.
centerWithBacking
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
}
}
}
}
Sources/iOS/FlatButton.swift
View file @
77a779df
...
@@ -35,4 +35,13 @@ open class FlatButton: Button {
...
@@ -35,4 +35,13 @@ open class FlatButton: Button {
super
.
prepare
()
super
.
prepare
()
cornerRadiusPreset
=
.
cornerRadius1
cornerRadiusPreset
=
.
cornerRadius1
}
}
open
override
func
apply
(
theme
:
Theme
)
{
super
.
apply
(
theme
:
theme
)
backgroundColor
=
.
clear
titleColor
=
theme
.
secondary
tintColor
=
theme
.
secondary
pulseColor
=
theme
.
secondary
}
}
}
Sources/iOS/IconButton.swift
View file @
77a779df
...
@@ -30,9 +30,33 @@
...
@@ -30,9 +30,33 @@
import
UIKit
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
{
open
class
IconButton
:
Button
{
/// A reference to IconButtonThemingStyle.
open
var
themingStyle
=
IconButtonThemingStyle
.
onBackground
open
override
func
prepare
()
{
open
override
func
prepare
()
{
super
.
prepare
()
super
.
prepare
()
pulseAnimation
=
.
center
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
}
}
}
}
Sources/iOS/Material+UIColor.swift
View file @
77a779df
...
@@ -62,3 +62,66 @@ public extension UIColor {
...
@@ -62,3 +62,66 @@ public extension UIColor {
self
.
init
(
argb
:
(
0xff000000
as
UInt32
)
|
rgb
)
self
.
init
(
argb
:
(
0xff000000
as
UInt32
)
|
rgb
)
}
}
}
}
internal
extension
UIColor
{
/// A tuple of the rgba components.
var
components
:
(
r
:
CGFloat
,
g
:
CGFloat
,
b
:
CGFloat
,
a
:
CGFloat
)
{
var
r
:
CGFloat
=
0
var
g
:
CGFloat
=
0
var
b
:
CGFloat
=
0
var
a
:
CGFloat
=
0
getRed
(
&
r
,
green
:
&
g
,
blue
:
&
b
,
alpha
:
&
a
)
return
(
r
,
g
,
b
,
a
)
}
/**
Blends given coverColor over this color.
- Parameter with coverColor: A UIColor.
- Returns: Resultant color of blending.
*/
func
blend
(
with
coverColor
:
UIColor
)
->
UIColor
{
/// Blends channels according to https://en.wikipedia.org/wiki/Alpha_compositing (see `over` operator).
func
blendChannel
(
value
:
CGFloat
,
bValue
:
CGFloat
,
alpha
:
CGFloat
,
bAlpha
:
CGFloat
)
->
CGFloat
{
return
((
1
-
alpha
)
*
bValue
*
bAlpha
+
alpha
*
value
)
/
(
alpha
+
bAlpha
*
(
1
-
alpha
))
}
let
(
r
,
g
,
b
,
a
)
=
coverColor
.
components
let
(
bR
,
bG
,
bB
,
bA
)
=
components
let
newR
=
blendChannel
(
value
:
r
,
bValue
:
bR
,
alpha
:
a
,
bAlpha
:
bA
)
let
newG
=
blendChannel
(
value
:
g
,
bValue
:
bG
,
alpha
:
a
,
bAlpha
:
bA
)
let
newB
=
blendChannel
(
value
:
b
,
bValue
:
bB
,
alpha
:
a
,
bAlpha
:
bA
)
let
newA
=
a
+
bA
*
(
1
-
a
)
return
UIColor
(
red
:
newR
,
green
:
newG
,
blue
:
newB
,
alpha
:
newA
)
}
/**
Adjusts brightness of the color by given value.
- Parameter by value: A CGFloat value.
- Returns: Adjusted color.
*/
func
adjustingBrightness
(
by
value
:
CGFloat
)
->
UIColor
{
var
h
:
CGFloat
=
0
var
s
:
CGFloat
=
0
var
b
:
CGFloat
=
0
var
a
:
CGFloat
=
0
getHue
(
&
h
,
saturation
:
&
s
,
brightness
:
&
b
,
alpha
:
&
a
)
return
UIColor
(
hue
:
h
,
saturation
:
s
,
brightness
:
(
b
+
value
)
.
clamp
(
0
,
1
),
alpha
:
1
)
}
/// A lighter version of the color.
var
lighter
:
UIColor
{
return
adjustingBrightness
(
by
:
0.1
)
}
/// A darker version of the color.
var
darker
:
UIColor
{
return
adjustingBrightness
(
by
:
-
0.1
)
}
}
Sources/iOS/NavigationBar.swift
View file @
77a779df
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
import
UIKit
import
UIKit
open
class
NavigationBar
:
UINavigationBar
{
open
class
NavigationBar
:
UINavigationBar
,
Themeable
{
/// Will layout the view.
/// Will layout the view.
open
var
willLayout
:
Bool
{
open
var
willLayout
:
Bool
{
return
0
<
bounds
.
width
&&
0
<
bounds
.
height
&&
nil
!=
superview
return
0
<
bounds
.
width
&&
0
<
bounds
.
height
&&
nil
!=
superview
...
@@ -168,7 +168,28 @@ open class NavigationBar: UINavigationBar {
...
@@ -168,7 +168,28 @@ open class NavigationBar: UINavigationBar {
let
image
=
UIImage
()
let
image
=
UIImage
()
shadowImage
=
image
shadowImage
=
image
setBackgroundImage
(
image
,
for
:
.
default
)
setBackgroundImage
(
image
,
for
:
.
default
)
backgroundColor
=
.
white
applyCurrentTheme
()
}
/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
backgroundColor
=
theme
.
primary
items
?
.
forEach
{
apply
(
theme
:
theme
,
to
:
$0
)
}
}
/**
Applies the given theme to the navigation item.
- Parameter theme: A Theme.
- Parameter to item: A UINavigationItem.
*/
private
func
apply
(
theme
:
Theme
,
to
item
:
UINavigationItem
)
{
Theme
.
apply
(
theme
:
theme
,
to
:
item
.
toolbar
)
item
.
toolbar
.
backgroundColor
=
.
clear
}
}
}
}
...
@@ -182,8 +203,11 @@ internal extension NavigationBar {
...
@@ -182,8 +203,11 @@ internal extension NavigationBar {
return
return
}
}
if
isThemingEnabled
{
apply
(
theme
:
.
current
,
to
:
item
)
}
let
toolbar
=
item
.
toolbar
let
toolbar
=
item
.
toolbar
toolbar
.
backgroundColor
=
.
clear
toolbar
.
interimSpace
=
interimSpace
toolbar
.
interimSpace
=
interimSpace
toolbar
.
contentEdgeInsets
=
contentEdgeInsets
toolbar
.
contentEdgeInsets
=
contentEdgeInsets
...
...
Sources/iOS/RaisedButton.swift
View file @
77a779df
...
@@ -35,6 +35,14 @@ open class RaisedButton: Button {
...
@@ -35,6 +35,14 @@ open class RaisedButton: Button {
super
.
prepare
()
super
.
prepare
()
depthPreset
=
.
depth1
depthPreset
=
.
depth1
cornerRadiusPreset
=
.
cornerRadius1
cornerRadiusPreset
=
.
cornerRadius1
backgroundColor
=
.
white
}
open
override
func
apply
(
theme
:
Theme
)
{
super
.
apply
(
theme
:
theme
)
backgroundColor
=
theme
.
secondary
titleColor
=
theme
.
onSecondary
pulseColor
=
theme
.
onSecondary
tintColor
=
theme
.
onSecondary
}
}
}
}
Sources/iOS/StatusBarController.swift
View file @
77a779df
...
@@ -120,6 +120,12 @@ open class StatusBarController: TransitionController {
...
@@ -120,6 +120,12 @@ open class StatusBarController: TransitionController {
super
.
prepare
()
super
.
prepare
()
prepareStatusBar
()
prepareStatusBar
()
}
}
open
override
func
apply
(
theme
:
Theme
)
{
super
.
apply
(
theme
:
theme
)
statusBar
.
backgroundColor
=
theme
.
primary
.
darker
}
}
}
fileprivate
extension
StatusBarController
{
fileprivate
extension
StatusBarController
{
...
...
Sources/iOS/Switch.swift
View file @
77a779df
...
@@ -30,12 +30,6 @@
...
@@ -30,12 +30,6 @@
import
UIKit
import
UIKit
@objc(SwitchStyle)
public
enum
SwitchStyle
:
Int
{
case
light
case
dark
}
@objc(SwitchState)
@objc(SwitchState)
public
enum
SwitchState
:
Int
{
public
enum
SwitchState
:
Int
{
case
on
case
on
...
@@ -59,7 +53,7 @@ public protocol SwitchDelegate {
...
@@ -59,7 +53,7 @@ public protocol SwitchDelegate {
func
switchDidChangeState
(
control
:
Switch
,
state
:
SwitchState
)
func
switchDidChangeState
(
control
:
Switch
,
state
:
SwitchState
)
}
}
open
class
Switch
:
UIControl
{
open
class
Switch
:
UIControl
,
Themeable
{
/// Will layout the view.
/// Will layout the view.
open
var
willLayout
:
Bool
{
open
var
willLayout
:
Bool
{
return
0
<
bounds
.
width
&&
0
<
bounds
.
height
&&
nil
!=
superview
return
0
<
bounds
.
width
&&
0
<
bounds
.
height
&&
nil
!=
superview
...
@@ -200,32 +194,6 @@ open class Switch: UIControl {
...
@@ -200,32 +194,6 @@ open class Switch: UIControl {
}
}
}
}
/// Switch style.
open
var
switchStyle
=
SwitchStyle
.
dark
{
didSet
{
switch
switchStyle
{
case
.
light
:
buttonOnColor
=
Color
.
blue
.
darken2
trackOnColor
=
Color
.
blue
.
lighten3
buttonOffColor
=
Color
.
blueGrey
.
lighten4
trackOffColor
=
Color
.
grey
.
lighten2
buttonOnDisabledColor
=
Color
.
grey
.
lighten2
trackOnDisabledColor
=
Color
.
grey
.
lighten2
buttonOffDisabledColor
=
Color
.
grey
.
lighten2
trackOffDisabledColor
=
Color
.
grey
.
lighten2
case
.
dark
:
buttonOnColor
=
Color
.
blue
.
lighten1
trackOnColor
=
Color
.
blue
.
lighten2
.
withAlphaComponent
(
0.5
)
buttonOffColor
=
Color
.
grey
.
lighten2
trackOffColor
=
Color
.
blueGrey
.
lighten4
.
withAlphaComponent
(
0.5
)
buttonOnDisabledColor
=
Color
.
grey
.
darken3
trackOnDisabledColor
=
Color
.
grey
.
lighten1
.
withAlphaComponent
(
0.2
)
buttonOffDisabledColor
=
Color
.
grey
.
darken3
trackOffDisabledColor
=
Color
.
grey
.
lighten1
.
withAlphaComponent
(
0.2
)
}
}
}
/// Switch size.
/// Switch size.
open
var
switchSize
=
SwitchSize
.
medium
{
open
var
switchSize
=
SwitchSize
.
medium
{
didSet
{
didSet
{
...
@@ -287,13 +255,12 @@ open class Switch: UIControl {
...
@@ -287,13 +255,12 @@ open class Switch: UIControl {
- Parameter style: A SwitchStyle value.
- Parameter style: A SwitchStyle value.
- Parameter size: A SwitchSize value.
- Parameter size: A SwitchSize value.
*/
*/
public
init
(
state
:
SwitchState
=
.
off
,
s
tyle
:
SwitchStyle
=
.
dark
,
s
ize
:
SwitchSize
=
.
medium
)
{
public
init
(
state
:
SwitchState
=
.
off
,
size
:
SwitchSize
=
.
medium
)
{
track
=
UIView
()
track
=
UIView
()
button
=
FABButton
()
button
=
FABButton
()
super
.
init
(
frame
:
.
zero
)
super
.
init
(
frame
:
.
zero
)
prepare
()
prepare
()
prepareSwitchState
(
state
:
state
)
prepareSwitchState
(
state
:
state
)
prepareSwitchStyle
(
style
:
style
)
prepareSwitchSize
(
size
:
size
)
prepareSwitchSize
(
size
:
size
)
}
}
...
@@ -356,8 +323,24 @@ open class Switch: UIControl {
...
@@ -356,8 +323,24 @@ open class Switch: UIControl {
prepareTrack
()
prepareTrack
()
prepareButton
()
prepareButton
()
prepareSwitchState
()
prepareSwitchState
()
prepareSwitchStyle
()
prepareSwitchSize
()
prepareSwitchSize
()
applyCurrentTheme
()
}
/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
buttonOnColor
=
theme
.
secondary
trackOnColor
=
theme
.
secondary
.
withAlphaComponent
(
0.60
)
buttonOffColor
=
theme
.
surface
.
blend
(
with
:
theme
.
onSurface
.
withAlphaComponent
(
0.15
)
.
blend
(
with
:
theme
.
secondary
.
withAlphaComponent
(
0.06
)))
trackOffColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.12
)
buttonOnDisabledColor
=
theme
.
surface
.
blend
(
with
:
theme
.
onSurface
.
withAlphaComponent
(
0.15
))
trackOnDisabledColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.15
)
buttonOffDisabledColor
=
buttonOnDisabledColor
trackOffDisabledColor
=
trackOnDisabledColor
}
}
}
}
...
@@ -565,15 +548,6 @@ fileprivate extension Switch {
...
@@ -565,15 +548,6 @@ fileprivate extension Switch {
}
}
/**
/**
Prepares the switchStyle property. This is used mainly to allow
init to set the state value and have an effect.
- Parameter style: The SwitchStyle to set.
*/
func
prepareSwitchStyle
(
style
:
SwitchStyle
=
.
light
)
{
switchStyle
=
style
}
/**
Prepares the switchSize property. This is used mainly to allow
Prepares the switchSize property. This is used mainly to allow
init to set the size value and have an effect.
init to set the size value and have an effect.
- Parameter size: The SwitchSize to set.
- Parameter size: The SwitchSize to set.
...
...
Sources/iOS/TabBar.swift
View file @
77a779df
...
@@ -614,6 +614,7 @@ internal extension TabBar {
...
@@ -614,6 +614,7 @@ internal extension TabBar {
*/
*/
func
finishLineTransition
(
isAnimated
:
Bool
=
true
)
{
func
finishLineTransition
(
isAnimated
:
Bool
=
true
)
{
line
.
motionViewTransition
.
finish
(
isAnimated
:
isAnimated
)
line
.
motionViewTransition
.
finish
(
isAnimated
:
isAnimated
)
line
.
transition
([])
}
}
/**
/**
...
@@ -622,6 +623,7 @@ internal extension TabBar {
...
@@ -622,6 +623,7 @@ internal extension TabBar {
*/
*/
func
cancelLineTransition
(
isAnimated
:
Bool
=
true
)
{
func
cancelLineTransition
(
isAnimated
:
Bool
=
true
)
{
line
.
motionViewTransition
.
cancel
(
isAnimated
:
isAnimated
)
line
.
motionViewTransition
.
cancel
(
isAnimated
:
isAnimated
)
line
.
transition
([])
}
}
}
}
...
...
Sources/iOS/TabsController.swift
View file @
77a779df
...
@@ -39,6 +39,12 @@ public enum TabBarAlignment: Int {
...
@@ -39,6 +39,12 @@ public enum TabBarAlignment: Int {
case
bottom
case
bottom
}
}
public
enum
TabBarThemingStyle
{
case
auto
case
primary
case
secondary
}
extension
UIViewController
{
extension
UIViewController
{
/// TabItem reference.
/// TabItem reference.
@objc
@objc
...
@@ -161,10 +167,14 @@ open class TabsController: TransitionController {
...
@@ -161,10 +167,14 @@ open class TabsController: TransitionController {
/// The tabBar alignment.
/// The tabBar alignment.
open
var
tabBarAlignment
=
TabBarAlignment
.
bottom
{
open
var
tabBarAlignment
=
TabBarAlignment
.
bottom
{
didSet
{
didSet
{
updateTabBarAlignment
()
layoutSubviews
()
layoutSubviews
()
}
}
}
}
/// The tabBar theming style.
open
var
tabBarThemingStyle
=
TabBarThemingStyle
.
auto
/**
/**
A UIPanGestureRecognizer property internally used for the interactive
A UIPanGestureRecognizer property internally used for the interactive
swipe.
swipe.
...
@@ -218,11 +228,55 @@ open class TabsController: TransitionController {
...
@@ -218,11 +228,55 @@ open class TabsController: TransitionController {
prepareTabBar
()
prepareTabBar
()
prepareTabItems
()
prepareTabItems
()
prepareSelectedIndexViewController
()
prepareSelectedIndexViewController
()
applyCurrentTheme
()
}
}
open
override
func
transition
(
to
viewController
:
UIViewController
,
completion
:
((
Bool
)
->
Void
)?)
{
open
override
func
transition
(
to
viewController
:
UIViewController
,
completion
:
((
Bool
)
->
Void
)?)
{
transition
(
to
:
viewController
,
isTriggeredByUserInteraction
:
false
,
completion
:
completion
)
transition
(
to
:
viewController
,
isTriggeredByUserInteraction
:
false
,
completion
:
completion
)
}
}
open
override
func
apply
(
theme
:
Theme
)
{
super
.
apply
(
theme
:
theme
)
switch
tabBarThemingStyle
{
case
.
auto
where
(
parent
is
NavigationController
||
parent
is
ToolbarController
)
&&
tabBarAlignment
==
.
top
:
fallthrough
case
.
primary
:
applyPrimary
(
theme
:
theme
)
default
:
applySecondary
(
theme
:
theme
)
}
}
}
private
extension
TabsController
{
/**
Applies theming taking primary color as base.
- Parameter theme: A Theme
*/
func
applyPrimary
(
theme
:
Theme
)
{
tabBar
.
lineColor
=
theme
.
onPrimary
.
withAlphaComponent
(
0.68
)
tabBar
.
backgroundColor
=
theme
.
primary
tabBar
.
setTabItemsColor
(
theme
.
onPrimary
,
for
:
.
normal
)
tabBar
.
setTabItemsColor
(
theme
.
onPrimary
,
for
:
.
selected
)
tabBar
.
setTabItemsColor
(
theme
.
onPrimary
,
for
:
.
highlighted
)
tabBar
.
isDividerHidden
=
true
}
/**
Applies theming taking secondary color as base.
- Parameter theme: A Theme
*/
func
applySecondary
(
theme
:
Theme
)
{
tabBar
.
lineColor
=
theme
.
secondary
tabBar
.
backgroundColor
=
theme
.
background
tabBar
.
setTabItemsColor
(
theme
.
onSurface
.
withAlphaComponent
(
0.60
),
for
:
.
normal
)
tabBar
.
setTabItemsColor
(
theme
.
secondary
,
for
:
.
selected
)
tabBar
.
setTabItemsColor
(
theme
.
secondary
,
for
:
.
highlighted
)
tabBar
.
dividerColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.12
)
}
}
}
fileprivate
extension
TabsController
{
fileprivate
extension
TabsController
{
...
@@ -273,9 +327,14 @@ fileprivate extension TabsController {
...
@@ -273,9 +327,14 @@ fileprivate extension TabsController {
/// Prepares the TabBar.
/// Prepares the TabBar.
func
prepareTabBar
()
{
func
prepareTabBar
()
{
tabBar
.
lineAlignment
=
.
bottom
==
tabBarAlignment
?
.
top
:
.
bottom
tabBar
.
_delegate
=
self
tabBar
.
_delegate
=
self
view
.
addSubview
(
tabBar
)
view
.
addSubview
(
tabBar
)
updateTabBarAlignment
()
}
func
updateTabBarAlignment
()
{
tabBar
.
lineAlignment
=
.
bottom
==
tabBarAlignment
?
.
top
:
.
bottom
tabBar
.
dividerAlignment
=
.
bottom
==
tabBarAlignment
?
.
top
:
.
bottom
}
}
/// Prepares the `tabBar.tabItems`.
/// Prepares the `tabBar.tabItems`.
...
...
Sources/iOS/TextField.swift
View file @
77a779df
...
@@ -63,7 +63,7 @@ public protocol TextFieldDelegate: UITextFieldDelegate {
...
@@ -63,7 +63,7 @@ public protocol TextFieldDelegate: UITextFieldDelegate {
optional
func
textField
(
textField
:
TextField
,
didClear
text
:
String
?)
optional
func
textField
(
textField
:
TextField
,
didClear
text
:
String
?)
}
}
open
class
TextField
:
UITextField
{
open
class
TextField
:
UITextField
,
Themeable
{
/// Minimum TextField text height.
/// Minimum TextField text height.
private
let
minimumTextHeight
:
CGFloat
=
32
private
let
minimumTextHeight
:
CGFloat
=
32
...
@@ -459,6 +459,25 @@ open class TextField: UITextField {
...
@@ -459,6 +459,25 @@ open class TextField: UITextField {
prepareTargetHandlers
()
prepareTargetHandlers
()
prepareTextAlignment
()
prepareTextAlignment
()
prepareRightView
()
prepareRightView
()
applyCurrentTheme
()
}
/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
placeholderActiveColor
=
theme
.
secondary
placeholderNormalColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.38
)
leftViewActiveColor
=
theme
.
secondary
leftViewNormalColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.38
)
dividerActiveColor
=
theme
.
secondary
dividerNormalColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.12
)
detailColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.38
)
textColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.87
)
}
}
}
}
...
...
Sources/iOS/TextView.swift
View file @
77a779df
...
@@ -87,7 +87,7 @@ public protocol TextViewDelegate : UITextViewDelegate {
...
@@ -87,7 +87,7 @@ public protocol TextViewDelegate : UITextViewDelegate {
optional
func
textView
(
textView
:
TextView
,
didProcessEditing
textStorage
:
TextStorage
,
text
:
String
,
range
:
NSRange
)
optional
func
textView
(
textView
:
TextView
,
didProcessEditing
textStorage
:
TextStorage
,
text
:
String
,
range
:
NSRange
)
}
}
open
class
TextView
:
UITextView
{
open
class
TextView
:
UITextView
,
Themeable
{
/// A boolean indicating whether the text is empty.
/// A boolean indicating whether the text is empty.
open
var
isEmpty
:
Bool
{
open
var
isEmpty
:
Bool
{
return
0
==
text
?
.
utf16
.
count
return
0
==
text
?
.
utf16
.
count
...
@@ -289,6 +289,7 @@ open class TextView: UITextView {
...
@@ -289,6 +289,7 @@ open class TextView: UITextView {
prepareNotificationHandlers
()
prepareNotificationHandlers
()
prepareRegularExpression
()
prepareRegularExpression
()
preparePlaceholderLabel
()
preparePlaceholderLabel
()
applyCurrentTheme
()
}
}
open
override
var
contentSize
:
CGSize
{
open
override
var
contentSize
:
CGSize
{
...
@@ -354,6 +355,15 @@ open class TextView: UITextView {
...
@@ -354,6 +355,15 @@ open class TextView: UITextView {
super
.
paste
(
sender
)
super
.
paste
(
sender
)
fixTypingFont
()
fixTypingFont
()
}
}
/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
textColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.87
)
placeholderColor
=
theme
.
onSurface
.
withAlphaComponent
(
0.38
)
}
}
}
fileprivate
extension
TextView
{
fileprivate
extension
TextView
{
...
...
Sources/iOS/Theme.swift
0 → 100644
View file @
77a779df
/*
* Copyright (C) 2015 - 2018, Daniel Dahan and CosmicMind, Inc. <http://cosmicmind.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of CosmicMind nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import
UIKit
import
Motion
public
protocol
Themeable
:
class
{
/**
Applies given theme.
- Parameter theme: A Theme.
*/
func
apply
(
theme
:
Theme
)
/// A boolean indicating if theming is enabled.
var
isThemingEnabled
:
Bool
{
get
set
}
}
public
struct
Theme
:
Hashable
{
/// The color displayed most frequently across the app.
public
var
primary
=
Color
.
blue
.
darken2
/// Accent color for some components such as FABMenu.
public
var
secondary
=
Color
.
blue
.
base
/// Background color for view controllers and some components.
public
var
background
=
Color
.
white
/// Background color for components such as cards, and dialogs.
public
var
surface
=
Color
.
white
/// Error color for components such as ErrorTextField.
public
var
error
=
Color
.
red
.
base
/// Text and iconography color to be used on primary color.
public
var
onPrimary
=
Color
.
white
/// Text and iconography color to be used on secondary color.
public
var
onSecondary
=
Color
.
white
/// Text and iconography color to be used on background color.
public
var
onBackground
=
Color
.
black
/// Text and iconography color to be used on surface color.
public
var
onSurface
=
Color
.
black
/// Text and iconography color to be used on error color.
public
var
onError
=
Color
.
white
/// An initializer.
public
init
()
{
}
}
public
extension
Theme
{
/// Current theme for Material.
static
private(set)
var
current
=
Theme
.
light
/// A light theme.
static
var
light
=
Theme
()
/// A dark theme.
static
var
dark
:
Theme
=
{
var
t
=
Theme
()
t
.
primary
=
UIColor
(
rgb
:
0x202020
)
t
.
secondary
=
Color
.
teal
.
base
t
.
background
=
UIColor
(
rgb
:
0x303030
)
t
.
surface
=
t
.
background
t
.
onBackground
=
.
white
t
.
onSurface
=
.
white
return
t
}()
}
public
extension
Theme
{
/**
Applies theme to the entire app.
- Parameter theme: A Theme.
*/
static
func
apply
(
theme
:
Theme
)
{
current
=
theme
guard
let
v
=
Application
.
rootViewController
else
{
return
}
apply
(
theme
:
theme
,
to
:
v
)
}
/**
Applies theme to the hierarchy of given view.
- Parameter theme: A Theme.
- Parameter to view: A UIView.
*/
static
func
apply
(
theme
:
Theme
,
to
view
:
UIView
)
{
guard
!
((
view
as?
Themeable
)?
.
isThemingEnabled
==
false
),
!
view
.
isProcessed
else
{
return
}
view
.
subviews
.
forEach
{
apply
(
theme
:
theme
,
to
:
$0
)
}
(
view
as?
Themeable
)?
.
apply
(
theme
:
theme
)
}
/**
Applies theme to the hierarchy of given view controller.
- Parameter theme: A Theme.
- Parameter to viewController: A UIViewController.
*/
static
func
apply
(
theme
:
Theme
,
to
viewController
:
UIViewController
)
{
guard
!
((
viewController
as?
Themeable
)?
.
isThemingEnabled
==
false
)
else
{
return
}
viewController
.
allChildren
.
forEach
{
apply
(
theme
:
theme
,
to
:
$0
)
$0
.
view
.
isProcessed
=
true
}
apply
(
theme
:
theme
,
to
:
viewController
.
view
)
viewController
.
allChildren
.
forEach
{
$0
.
view
.
isProcessed
=
false
}
(
viewController
as?
Themeable
)?
.
apply
(
theme
:
theme
)
}
/**
Applies provided theme for the components created within the given block
without chaging app's theme.
- Parameter theme: A Theme.
- Parameter for block: A code block.
*/
static
func
applying
(
theme
:
Theme
,
for
execute
:
()
->
Void
)
{
let
v
=
current
current
=
theme
execute
()
current
=
v
}
}
/// A memory reference to the isThemingEnabled for Themeable NSObject subclasses.
private
var
IsThemingEnabledKey
:
UInt8
=
0
public
extension
Themeable
where
Self
:
NSObject
{
/// A boolean indicating if theming is enabled.
var
isThemingEnabled
:
Bool
{
get
{
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
IsThemingEnabledKey
)
{
true
}
}
set
(
value
)
{
AssociatedObject
.
set
(
base
:
self
,
key
:
&
IsThemingEnabledKey
,
value
:
value
)
}
}
/// Applies current theme to itself if theming is enabled.
internal
func
applyCurrentTheme
()
{
guard
isThemingEnabled
else
{
return
}
apply
(
theme
:
.
current
)
}
}
private
extension
UIViewController
{
/// Returns all possible child view controllers.
var
allChildren
:
[
UIViewController
]
{
var
all
=
children
if
let
v
=
self
as?
TabsController
{
all
+=
v
.
viewControllers
}
if
let
v
=
presentedViewController
,
v
.
presentingViewController
===
self
{
all
.
append
(
v
)
}
return
all
}
}
/// A memory reference to the isProcessed for UIView.
private
var
IsProcessedKey
:
UInt8
=
0
private
extension
UIView
{
/// A boolean indicating if view is already themed.
var
isProcessed
:
Bool
{
get
{
return
AssociatedObject
.
get
(
base
:
self
,
key
:
&
IsProcessedKey
)
{
false
}
}
set
(
value
)
{
AssociatedObject
.
set
(
base
:
self
,
key
:
&
IsProcessedKey
,
value
:
value
)
}
}
}
Sources/iOS/Toolbar.swift
View file @
77a779df
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
import
UIKit
import
UIKit
open
class
Toolbar
:
Bar
{
open
class
Toolbar
:
Bar
,
Themeable
{
/// A convenience property to set the titleLabel.text.
/// A convenience property to set the titleLabel.text.
@IBInspectable
@IBInspectable
open
var
title
:
String
?
{
open
var
title
:
String
?
{
...
@@ -63,6 +63,24 @@ open class Toolbar: Bar {
...
@@ -63,6 +63,24 @@ open class Toolbar: Bar {
@IBInspectable
@IBInspectable
public
let
detailLabel
=
UILabel
()
public
let
detailLabel
=
UILabel
()
open
override
var
leftViews
:
[
UIView
]
{
didSet
{
prepareIconButtons
(
leftViews
)
}
}
open
override
var
centerViews
:
[
UIView
]
{
didSet
{
prepareIconButtons
(
centerViews
)
}
}
open
override
var
rightViews
:
[
UIView
]
{
didSet
{
prepareIconButtons
(
rightViews
)
}
}
/**
/**
An initializer that initializes the object with a NSCoder object.
An initializer that initializes the object with a NSCoder object.
- Parameter aDecoder: A NSCoder instance.
- Parameter aDecoder: A NSCoder instance.
...
@@ -129,6 +147,29 @@ open class Toolbar: Bar {
...
@@ -129,6 +147,29 @@ open class Toolbar: Bar {
prepareDetailLabel
()
prepareDetailLabel
()
}
}
/**
Applies the given theme.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
backgroundColor
=
theme
.
primary
(
leftViews
+
rightViews
+
centerViews
)
.
forEach
{
guard
let
v
=
$0
as?
IconButton
,
v
.
isThemingEnabled
else
{
return
}
v
.
apply
(
theme
:
theme
)
}
if
!
((
titleLabel
as?
Themeable
)?
.
isThemingEnabled
==
false
)
{
titleLabel
.
textColor
=
theme
.
onPrimary
}
if
!
((
detailLabel
as?
Themeable
)?
.
isThemingEnabled
==
false
)
{
detailLabel
.
textColor
=
theme
.
onPrimary
}
}
/// A reference to titleLabel.textAlignment observation.
/// A reference to titleLabel.textAlignment observation.
private
var
titleLabelTextAlignmentObserver
:
NSKeyValueObservation
!
private
var
titleLabelTextAlignmentObserver
:
NSKeyValueObservation
!
}
}
...
@@ -152,4 +193,12 @@ private extension Toolbar {
...
@@ -152,4 +193,12 @@ private extension Toolbar {
detailLabel
.
font
=
RobotoFont
.
regular
(
with
:
12
)
detailLabel
.
font
=
RobotoFont
.
regular
(
with
:
12
)
detailLabel
.
textColor
=
Color
.
darkText
.
secondary
detailLabel
.
textColor
=
Color
.
darkText
.
secondary
}
}
func
prepareIconButtons
(
_
views
:
[
UIView
])
{
views
.
forEach
{
(
$0
as?
IconButton
)?
.
themingStyle
=
.
onPrimary
}
applyCurrentTheme
()
}
}
}
Sources/iOS/ViewController.swift
View file @
77a779df
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
import
UIKit
import
UIKit
open
class
ViewController
:
UIViewController
{
open
class
ViewController
:
UIViewController
,
Themeable
{
open
override
func
viewDidLoad
()
{
open
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
super
.
viewDidLoad
()
prepare
()
prepare
()
...
@@ -45,8 +45,8 @@ open class ViewController: UIViewController {
...
@@ -45,8 +45,8 @@ open class ViewController: UIViewController {
*/
*/
open
func
prepare
()
{
open
func
prepare
()
{
view
.
clipsToBounds
=
true
view
.
clipsToBounds
=
true
view
.
backgroundColor
=
.
white
view
.
contentScaleFactor
=
Screen
.
scale
view
.
contentScaleFactor
=
Screen
.
scale
applyCurrentTheme
()
}
}
open
override
func
viewWillLayoutSubviews
()
{
open
override
func
viewWillLayoutSubviews
()
{
...
@@ -61,4 +61,12 @@ open class ViewController: UIViewController {
...
@@ -61,4 +61,12 @@ open class ViewController: UIViewController {
have a certain need.
have a certain need.
*/
*/
open
func
layoutSubviews
()
{
}
open
func
layoutSubviews
()
{
}
/**
Applies given theme to the view controller.
- Parameter theme: A Theme.
*/
open
func
apply
(
theme
:
Theme
)
{
view
.
backgroundColor
=
theme
.
background
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment