Commit a6ae3833 by Daniel Dahan

removed files until refactor is done

parent bdd34155
......@@ -7,52 +7,21 @@
objects = {
/* Begin PBXBuildFile section */
657CD02A1B8EE0D3008C0029 /* MaterialCardView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9A94D1081B8A3F5100F586A5 /* MaterialCardView.swift */; settings = {ATTRIBUTES = (Public, ); }; };
657CD02C1B8EE0D3008C0029 /* SideNavigationViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65B965861B8BEEC60055B139 /* SideNavigationViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
657CD02D1B8EE0D3008C0029 /* MaterialButton.swift in Headers */ = {isa = PBXBuildFile; fileRef = 65B9657D1B8A7C330055B139 /* MaterialButton.swift */; settings = {ATTRIBUTES = (Public, ); }; };
657CD02F1B8EE0D3008C0029 /* ImageCardView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9A94D10A1B8A485C00F586A5 /* ImageCardView.swift */; settings = {ATTRIBUTES = (Public, ); }; };
65B9657E1B8A7C330055B139 /* MaterialButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65B9657D1B8A7C330055B139 /* MaterialButton.swift */; };
65B965871B8BEEC60055B139 /* SideNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65B965861B8BEEC60055B139 /* SideNavigationViewController.swift */; };
65BDD1451BB5B8B8006F7F2B /* MaterialTheme+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD1441BB5B8B8006F7F2B /* MaterialTheme+View.swift */; settings = {ASSET_TAGS = (); }; };
65BDD1471BB5B916006F7F2B /* MaterialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD1461BB5B916006F7F2B /* MaterialView.swift */; settings = {ASSET_TAGS = (); }; };
65BDD1491BB5DC98006F7F2B /* MaterialTheme+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD1481BB5DC98006F7F2B /* MaterialTheme+Color.swift */; settings = {ASSET_TAGS = (); }; };
65BDD14B1BB5DD02006F7F2B /* MaterialTheme+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD14A1BB5DD02006F7F2B /* MaterialTheme+Font.swift */; settings = {ASSET_TAGS = (); }; };
65BDD1491BB5DC98006F7F2B /* MaterialColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD1481BB5DC98006F7F2B /* MaterialColor.swift */; settings = {ASSET_TAGS = (); }; };
65BDD14B1BB5DD02006F7F2B /* MaterialFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD14A1BB5DD02006F7F2B /* MaterialFont.swift */; settings = {ASSET_TAGS = (); }; };
65BDD14D1BB5ED9F006F7F2B /* MaterialTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD14C1BB5ED9F006F7F2B /* MaterialTheme.swift */; settings = {ASSET_TAGS = (); }; };
65BDD14F1BB5EE4A006F7F2B /* MaterialGravity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BDD14E1BB5EE4A006F7F2B /* MaterialGravity.swift */; settings = {ASSET_TAGS = (); }; };
65DBE4201B9A9244000C804F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 65DBE41E1B9A9244000C804F /* Roboto-Bold.ttf */; };
65DBE4211B9A9244000C804F /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 65DBE41F1B9A9244000C804F /* Roboto-Thin.ttf */; };
962F3E531BACA68C0004B8AD /* NavigationBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 962F3E521BACA68C0004B8AD /* NavigationBarView.swift */; };
962F3E541BACA7FB0004B8AD /* NavigationBarView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 962F3E521BACA68C0004B8AD /* NavigationBarView.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832421B88DFD80015F710 /* MaterialKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 963832361B88DFD80015F710 /* MaterialKit.framework */; };
9638325A1B88E31A0015F710 /* MaterialKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832581B88E31A0015F710 /* MaterialKitTests.swift */; };
963832691B88E5BF0015F710 /* Capture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9638325E1B88E5BF0015F710 /* Capture.swift */; };
9638326A1B88E5BF0015F710 /* CapturePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9638325F1B88E5BF0015F710 /* CapturePreview.swift */; };
9638326B1B88E5BF0015F710 /* FabButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832601B88E5BF0015F710 /* FabButton.swift */; };
9638326C1B88E5BF0015F710 /* FlatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832611B88E5BF0015F710 /* FlatButton.swift */; };
963832701B88E5BF0015F710 /* RaisedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832651B88E5BF0015F710 /* RaisedButton.swift */; };
963832711B88E5BF0015F710 /* MaterialText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832661B88E5BF0015F710 /* MaterialText.swift */; };
963832721B88E5BF0015F710 /* MaterialTextStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832671B88E5BF0015F710 /* MaterialTextStorage.swift */; };
963832731B88E5BF0015F710 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832681B88E5BF0015F710 /* TextView.swift */; };
9638327E1B89070E0015F710 /* MaterialText.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832661B88E5BF0015F710 /* MaterialText.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9638327F1B89070E0015F710 /* MaterialTextStorage.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832671B88E5BF0015F710 /* MaterialTextStorage.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832801B89070E0015F710 /* TextView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832681B88E5BF0015F710 /* TextView.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832811B89070E0015F710 /* FabButton.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832601B88E5BF0015F710 /* FabButton.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832821B89070E0015F710 /* FlatButton.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832611B88E5BF0015F710 /* FlatButton.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832831B89070E0015F710 /* RaisedButton.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832651B88E5BF0015F710 /* RaisedButton.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832841B89070E0015F710 /* Capture.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9638325E1B88E5BF0015F710 /* Capture.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832851B89070E0015F710 /* CapturePreview.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9638325F1B88E5BF0015F710 /* CapturePreview.swift */; settings = {ATTRIBUTES = (Public, ); }; };
963832881B8908180015F710 /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963832871B8908180015F710 /* Layout.swift */; };
963832891B89097D0015F710 /* Layout.swift in Headers */ = {isa = PBXBuildFile; fileRef = 963832871B8908180015F710 /* Layout.swift */; settings = {ATTRIBUTES = (Public, ); }; };
96B57D4E1B90AF7D00DE7BBB /* MaterialTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B57D4D1B90AF7D00DE7BBB /* MaterialTheme.swift */; };
96C910ED1B95804B00E7CE5C /* MaterialTheme.swift in Headers */ = {isa = PBXBuildFile; fileRef = 96B57D4D1B90AF7D00DE7BBB /* MaterialTheme.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9A94D0F91B895C8C00F586A5 /* Roboto.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9AAC38531B89559900FE6B2D /* Roboto.swift */; settings = {ATTRIBUTES = (Public, ); }; };
9A94D0FA1B895EA500F586A5 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 963832631B88E5BF0015F710 /* LICENSE */; };
9A94D0FB1B895EA500F586A5 /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9AAC38591B8956E300FE6B2D /* Roboto-Regular.ttf */; };
9A94D0FC1B895EA500F586A5 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9AAC38571B8956CF00FE6B2D /* Roboto-Medium.ttf */; };
9A94D0FD1B895EA500F586A5 /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9AAC38551B8956C500FE6B2D /* Roboto-Light.ttf */; };
9A94D1091B8A3F5100F586A5 /* MaterialCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A94D1081B8A3F5100F586A5 /* MaterialCardView.swift */; };
9A94D10B1B8A485C00F586A5 /* ImageCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A94D10A1B8A485C00F586A5 /* ImageCardView.swift */; };
9AAC384D1B89528900FE6B2D /* BasicCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AAC384C1B89528900FE6B2D /* BasicCardView.swift */; };
9AAC38541B89559900FE6B2D /* Roboto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AAC38531B89559900FE6B2D /* Roboto.swift */; };
9AAC385F1B8957A200FE6B2D /* BasicCardView.swift in Headers */ = {isa = PBXBuildFile; fileRef = 9AAC384C1B89528900FE6B2D /* BasicCardView.swift */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -66,12 +35,11 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
65B9657D1B8A7C330055B139 /* MaterialButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialButton.swift; sourceTree = "<group>"; };
65B965861B8BEEC60055B139 /* SideNavigationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideNavigationViewController.swift; sourceTree = "<group>"; };
65BDD1441BB5B8B8006F7F2B /* MaterialTheme+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MaterialTheme+View.swift"; sourceTree = "<group>"; };
65BDD1461BB5B916006F7F2B /* MaterialView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialView.swift; sourceTree = "<group>"; };
65BDD1481BB5DC98006F7F2B /* MaterialTheme+Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MaterialTheme+Color.swift"; sourceTree = "<group>"; };
65BDD14A1BB5DD02006F7F2B /* MaterialTheme+Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MaterialTheme+Font.swift"; sourceTree = "<group>"; };
65BDD1481BB5DC98006F7F2B /* MaterialColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialColor.swift; sourceTree = "<group>"; };
65BDD14A1BB5DD02006F7F2B /* MaterialFont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialFont.swift; sourceTree = "<group>"; };
65BDD14C1BB5ED9F006F7F2B /* MaterialTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialTheme.swift; sourceTree = "<group>"; };
65BDD14E1BB5EE4A006F7F2B /* MaterialGravity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialGravity.swift; sourceTree = "<group>"; };
65DBE41E1B9A9244000C804F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
65DBE41F1B9A9244000C804F /* Roboto-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Thin.ttf"; sourceTree = "<group>"; };
962F3E521BACA68C0004B8AD /* NavigationBarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBarView.swift; sourceTree = "<group>"; };
......@@ -80,21 +48,7 @@
963832541B88E30F0015F710 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
963832581B88E31A0015F710 /* MaterialKitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialKitTests.swift; sourceTree = "<group>"; };
963832591B88E31A0015F710 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9638325E1B88E5BF0015F710 /* Capture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capture.swift; sourceTree = "<group>"; };
9638325F1B88E5BF0015F710 /* CapturePreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapturePreview.swift; sourceTree = "<group>"; };
963832601B88E5BF0015F710 /* FabButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FabButton.swift; sourceTree = "<group>"; };
963832611B88E5BF0015F710 /* FlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlatButton.swift; sourceTree = "<group>"; };
963832631B88E5BF0015F710 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
963832651B88E5BF0015F710 /* RaisedButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RaisedButton.swift; sourceTree = "<group>"; };
963832661B88E5BF0015F710 /* MaterialText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialText.swift; sourceTree = "<group>"; };
963832671B88E5BF0015F710 /* MaterialTextStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialTextStorage.swift; sourceTree = "<group>"; };
963832681B88E5BF0015F710 /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; };
963832871B8908180015F710 /* Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Layout.swift; sourceTree = "<group>"; };
96B57D4D1B90AF7D00DE7BBB /* MaterialTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialTheme.swift; sourceTree = "<group>"; };
9A94D1081B8A3F5100F586A5 /* MaterialCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialCardView.swift; sourceTree = "<group>"; };
9A94D10A1B8A485C00F586A5 /* ImageCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCardView.swift; sourceTree = "<group>"; };
9AAC384C1B89528900FE6B2D /* BasicCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicCardView.swift; sourceTree = "<group>"; };
9AAC38531B89559900FE6B2D /* Roboto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Roboto.swift; sourceTree = "<group>"; };
9AAC38551B8956C500FE6B2D /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
9AAC38571B8956CF00FE6B2D /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; };
9AAC38591B8956E300FE6B2D /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
......@@ -124,7 +78,6 @@
children = (
65BDD1461BB5B916006F7F2B /* MaterialView.swift */,
962F3E521BACA68C0004B8AD /* NavigationBarView.swift */,
65B965861B8BEEC60055B139 /* SideNavigationViewController.swift */,
);
name = View;
sourceTree = "<group>";
......@@ -154,12 +107,7 @@
9638325C1B88E3420015F710 /* Supporting Files */,
96B57D4C1B90AF6A00DE7BBB /* Theme */,
9AAC38521B89553800FE6B2D /* Font */,
963832861B8907FE0015F710 /* Layout */,
65B965851B8BEEB00055B139 /* View */,
963832761B88E8990015F710 /* Text */,
963832751B88E87B0015F710 /* Button */,
9AAC384B1B89524E00FE6B2D /* Card */,
963832741B88E86B0015F710 /* Capture */,
);
path = Source;
sourceTree = "<group>";
......@@ -189,65 +137,17 @@
name = "Supporting Files";
sourceTree = "<group>";
};
963832741B88E86B0015F710 /* Capture */ = {
isa = PBXGroup;
children = (
9638325E1B88E5BF0015F710 /* Capture.swift */,
9638325F1B88E5BF0015F710 /* CapturePreview.swift */,
);
name = Capture;
sourceTree = "<group>";
};
963832751B88E87B0015F710 /* Button */ = {
isa = PBXGroup;
children = (
65B9657D1B8A7C330055B139 /* MaterialButton.swift */,
963832601B88E5BF0015F710 /* FabButton.swift */,
963832611B88E5BF0015F710 /* FlatButton.swift */,
963832651B88E5BF0015F710 /* RaisedButton.swift */,
);
name = Button;
sourceTree = "<group>";
};
963832761B88E8990015F710 /* Text */ = {
isa = PBXGroup;
children = (
963832661B88E5BF0015F710 /* MaterialText.swift */,
963832671B88E5BF0015F710 /* MaterialTextStorage.swift */,
963832681B88E5BF0015F710 /* TextView.swift */,
);
name = Text;
sourceTree = "<group>";
};
963832861B8907FE0015F710 /* Layout */ = {
isa = PBXGroup;
children = (
963832871B8908180015F710 /* Layout.swift */,
);
name = Layout;
sourceTree = "<group>";
};
96B57D4C1B90AF6A00DE7BBB /* Theme */ = {
isa = PBXGroup;
children = (
96B57D4D1B90AF7D00DE7BBB /* MaterialTheme.swift */,
65BDD1441BB5B8B8006F7F2B /* MaterialTheme+View.swift */,
65BDD1481BB5DC98006F7F2B /* MaterialTheme+Color.swift */,
65BDD14A1BB5DD02006F7F2B /* MaterialTheme+Font.swift */,
65BDD14C1BB5ED9F006F7F2B /* MaterialTheme.swift */,
65BDD1481BB5DC98006F7F2B /* MaterialColor.swift */,
65BDD14A1BB5DD02006F7F2B /* MaterialFont.swift */,
65BDD14E1BB5EE4A006F7F2B /* MaterialGravity.swift */,
);
name = Theme;
sourceTree = "<group>";
};
9AAC384B1B89524E00FE6B2D /* Card */ = {
isa = PBXGroup;
children = (
9A94D1081B8A3F5100F586A5 /* MaterialCardView.swift */,
9AAC384C1B89528900FE6B2D /* BasicCardView.swift */,
9A94D10A1B8A485C00F586A5 /* ImageCardView.swift */,
);
name = Card;
sourceTree = "<group>";
};
9AAC38521B89553800FE6B2D /* Font */ = {
isa = PBXGroup;
children = (
......@@ -256,7 +156,6 @@
9AAC38591B8956E300FE6B2D /* Roboto-Regular.ttf */,
9AAC38571B8956CF00FE6B2D /* Roboto-Medium.ttf */,
9AAC38551B8956C500FE6B2D /* Roboto-Light.ttf */,
9AAC38531B89559900FE6B2D /* Roboto.swift */,
);
name = Font;
sourceTree = "<group>";
......@@ -268,22 +167,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
9AAC385F1B8957A200FE6B2D /* BasicCardView.swift in Headers */,
9638327E1B89070E0015F710 /* MaterialText.swift in Headers */,
9638327F1B89070E0015F710 /* MaterialTextStorage.swift in Headers */,
963832801B89070E0015F710 /* TextView.swift in Headers */,
963832811B89070E0015F710 /* FabButton.swift in Headers */,
963832821B89070E0015F710 /* FlatButton.swift in Headers */,
963832831B89070E0015F710 /* RaisedButton.swift in Headers */,
963832841B89070E0015F710 /* Capture.swift in Headers */,
9A94D0F91B895C8C00F586A5 /* Roboto.swift in Headers */,
963832851B89070E0015F710 /* CapturePreview.swift in Headers */,
963832891B89097D0015F710 /* Layout.swift in Headers */,
657CD02A1B8EE0D3008C0029 /* MaterialCardView.swift in Headers */,
657CD02C1B8EE0D3008C0029 /* SideNavigationViewController.swift in Headers */,
657CD02D1B8EE0D3008C0029 /* MaterialButton.swift in Headers */,
96C910ED1B95804B00E7CE5C /* MaterialTheme.swift in Headers */,
657CD02F1B8EE0D3008C0029 /* ImageCardView.swift in Headers */,
962F3E541BACA7FB0004B8AD /* NavigationBarView.swift in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
......@@ -392,27 +275,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
963832691B88E5BF0015F710 /* Capture.swift in Sources */,
65BDD1471BB5B916006F7F2B /* MaterialView.swift in Sources */,
9A94D10B1B8A485C00F586A5 /* ImageCardView.swift in Sources */,
96B57D4E1B90AF7D00DE7BBB /* MaterialTheme.swift in Sources */,
962F3E531BACA68C0004B8AD /* NavigationBarView.swift in Sources */,
9638326B1B88E5BF0015F710 /* FabButton.swift in Sources */,
9A94D1091B8A3F5100F586A5 /* MaterialCardView.swift in Sources */,
65B965871B8BEEC60055B139 /* SideNavigationViewController.swift in Sources */,
65BDD14B1BB5DD02006F7F2B /* MaterialTheme+Font.swift in Sources */,
65BDD1451BB5B8B8006F7F2B /* MaterialTheme+View.swift in Sources */,
9638326C1B88E5BF0015F710 /* FlatButton.swift in Sources */,
963832711B88E5BF0015F710 /* MaterialText.swift in Sources */,
9638326A1B88E5BF0015F710 /* CapturePreview.swift in Sources */,
65BDD1491BB5DC98006F7F2B /* MaterialTheme+Color.swift in Sources */,
9AAC38541B89559900FE6B2D /* Roboto.swift in Sources */,
65B9657E1B8A7C330055B139 /* MaterialButton.swift in Sources */,
963832881B8908180015F710 /* Layout.swift in Sources */,
9AAC384D1B89528900FE6B2D /* BasicCardView.swift in Sources */,
963832731B88E5BF0015F710 /* TextView.swift in Sources */,
963832721B88E5BF0015F710 /* MaterialTextStorage.swift in Sources */,
963832701B88E5BF0015F710 /* RaisedButton.swift in Sources */,
65BDD14F1BB5EE4A006F7F2B /* MaterialGravity.swift in Sources */,
65BDD14B1BB5DD02006F7F2B /* MaterialFont.swift in Sources */,
65BDD1491BB5DC98006F7F2B /* MaterialColor.swift in Sources */,
65BDD14D1BB5ED9F006F7F2B /* MaterialTheme.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
//
// Copyright (C) 1615 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class BasicCardView : MaterialCardView, Comparable {
//
// :name: layoutConstraints
//
internal lazy var layoutConstraints: Array<NSLayoutConstraint> = Array<NSLayoutConstraint>()
/**
:name: titleLabelVerticalInset
*/
public var titleLabelVerticalInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
titleLabelTopInset = titleLabelVerticalInset
titleLabelBottomInset = titleLabelVerticalInset
}
}
/**
:name: titleLabelTopInset
*/
public var titleLabelTopInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: titleLabelBottomInset
*/
public var titleLabelBottomInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: titleLabelHorizontalInset
*/
public var titleLabelHorizontalInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
titleLabelLeftInset = titleLabelHorizontalInset
titleLabelRightInset = titleLabelHorizontalInset
}
}
/**
:name: titleLabelLeftInset
*/
public var titleLabelLeftInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: titleLabelRightInset
*/
public var titleLabelRightInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelVerticalInset
*/
public var detailLabelVerticalInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
detailLabelTopInset = detailLabelVerticalInset
detailLabelBottomInset = detailLabelVerticalInset
}
}
/**
:name: detailLabelTopInset
*/
public var detailLabelTopInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelBottomInset
*/
public var detailLabelBottomInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelHorizontalInset
*/
public var detailLabelHorizontalInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
detailLabelLeftInset = detailLabelHorizontalInset
detailLabelRightInset = detailLabelHorizontalInset
}
}
/**
:name: detailLabelLeftInset
*/
public var detailLabelLeftInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelRightInset
*/
public var detailLabelRightInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: buttonVerticalInset
*/
public var buttonVerticalInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
buttonTopInset = buttonVerticalInset
buttonBottomInset = buttonVerticalInset
}
}
/**
:name: buttonTopInset
*/
public var buttonTopInset: CGFloat = MaterialTheme.cardVerticalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: buttonBottomInset
*/
public var buttonBottomInset: CGFloat = MaterialTheme.cardVerticalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: buttonHorizontalInset
*/
public var buttonHorizontalInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
buttonLeftInset = buttonHorizontalInset
buttonRightInset = buttonHorizontalInset
}
}
/**
:name: buttonLeftInset
*/
public var buttonLeftInset: CGFloat = MaterialTheme.cardHorizontalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: buttonRightInset
*/
public var buttonRightInset: CGFloat = MaterialTheme.cardHorizontalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: shadow
*/
public var shadow: Bool = true {
didSet {
false == shadow ? removeShadow() : prepareShadow()
reloadView()
}
}
/**
:name: maximumTitleLabelHeight
*/
public var maximumTitleLabelHeight: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: titleLabelContainer
*/
public private(set) var titleLabelContainer: UIView?
/**
:name: titleLabel
*/
public var titleLabel: UILabel? {
didSet {
if let t = titleLabel {
// container
if nil == titleLabelContainer {
titleLabelContainer = UIView()
titleLabelContainer!.translatesAutoresizingMaskIntoConstraints = false
titleLabelContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(titleLabelContainer!)
}
// text
titleLabelContainer!.addSubview(t)
t.translatesAutoresizingMaskIntoConstraints = false
t.backgroundColor = MaterialTheme.color.clear.base
t.font = Roboto.regular
t.numberOfLines = 0
t.lineBreakMode = .ByTruncatingTail
t.textColor = MaterialTheme.color.white.base
} else {
titleLabelContainer?.removeFromSuperview()
titleLabelContainer = nil
}
reloadView()
}
}
/**
:name: maximumDetailLabelHeight
*/
public var maximumDetailLabelHeight: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: detailLabelContainer
*/
public private(set) var detailLabelContainer: UIView?
/**
:name: detailLabel
*/
public var detailLabel: UILabel? {
didSet {
if let l = detailLabel {
// container
if nil == detailLabelContainer {
detailLabelContainer = UIView()
detailLabelContainer!.translatesAutoresizingMaskIntoConstraints = false
detailLabelContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(detailLabelContainer!)
}
// text
detailLabelContainer!.addSubview(l)
l.translatesAutoresizingMaskIntoConstraints = false
l.textColor = MaterialTheme.color.white.base
l.backgroundColor = MaterialTheme.color.clear.base
l.font = Roboto.light
l.numberOfLines = 0
l.lineBreakMode = .ByTruncatingTail
} else {
detailLabelContainer?.removeFromSuperview()
detailLabelContainer = nil
}
reloadView()
}
}
/**
:name: divider
*/
public var divider: UIView? {
didSet {
if let d = divider {
d.translatesAutoresizingMaskIntoConstraints = false
d.backgroundColor = MaterialTheme.color.blueGrey.darken1
addSubview(d)
} else {
divider?.removeFromSuperview()
}
reloadView()
}
}
/**
:name: buttonsContainer
*/
public private(set) var buttonsContainer: UIView?
/**
:name: leftButtons
*/
public var leftButtons: Array<MaterialButton>? {
didSet {
if nil == rightButtons && nil == leftButtons {
buttonsContainer?.removeFromSuperview()
buttonsContainer = nil
} else if nil == buttonsContainer {
buttonsContainer = UIView()
buttonsContainer!.translatesAutoresizingMaskIntoConstraints = false
buttonsContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(buttonsContainer!)
} else {
for v in buttonsContainer!.subviews {
v.removeFromSuperview()
}
}
reloadView()
}
}
/**
:name: rightButtons
*/
public var rightButtons: Array<MaterialButton>? {
didSet {
if nil == rightButtons && nil == leftButtons {
buttonsContainer?.removeFromSuperview()
buttonsContainer = nil
} else if nil == buttonsContainer {
buttonsContainer = UIView()
buttonsContainer!.translatesAutoresizingMaskIntoConstraints = false
buttonsContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(buttonsContainer!)
}
reloadView()
}
}
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public convenience init?(titleLabel: UILabel? = nil, detailLabel: UILabel? = nil, divider: UIView? = nil, leftButtons: Array<MaterialButton>? = nil, rightButtons: Array<MaterialButton>? = nil) {
self.init(frame: CGRectZero)
prepareProperties(titleLabel, detailLabel: detailLabel, divider: divider, leftButtons: leftButtons, rightButtons: rightButtons)
}
/**
:name: init
*/
public required init(frame: CGRect) {
super.init(frame: frame)
}
/**
:name: isEqual
*/
public override func isEqual(object: AnyObject?) -> Bool {
if let rhs = object as? BasicCardView {
return tag == rhs.tag
}
return false
}
/**
:name: reloadView
*/
public func reloadView() {
// clear all constraints
NSLayoutConstraint.deactivateConstraints(layoutConstraints)
layoutConstraints.removeAll(keepCapacity: false)
// detect all components and create constraints
var verticalFormat: String = "V:|"
var views: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
// title
if nil != titleLabel {
// clear for updated constraints
titleLabelContainer!.removeConstraints(titleLabelContainer!.constraints)
// container
layoutConstraints += Layout.constraint("H:|[titleLabelContainer]|", options: [], metrics: nil, views: ["titleLabelContainer": titleLabelContainer!])
verticalFormat += "[titleLabelContainer]"
views["titleLabelContainer"] = titleLabelContainer!
// common text
if 0 == maximumTitleLabelHeight {
Layout.expandToParentWithPad(titleLabelContainer!, child: titleLabel!, top: titleLabelTopInset, left: titleLabelLeftInset, bottom: titleLabelBottomInset, right: titleLabelRightInset)
} else {
Layout.expandToParentHorizontallyWithPad(titleLabelContainer!, child: titleLabel!, left: titleLabelLeftInset, right: titleLabelRightInset)
titleLabelContainer!.addConstraints(Layout.constraint("V:|-(titleLabelTopInset)-[titleLabel(<=maximumTitleLabelHeight)]-(titleLabelBottomInset)-|", options: [], metrics: ["titleLabelTopInset": titleLabelTopInset, "titleLabelBottomInset": titleLabelBottomInset, "maximumTitleLabelHeight": maximumTitleLabelHeight], views: ["titleLabel": titleLabel!]))
}
}
// detail
if nil != detailLabel {
// clear for updated constraints
detailLabelContainer!.removeConstraints(detailLabelContainer!.constraints)
// container
layoutConstraints += Layout.constraint("H:|[detailLabelContainer]|", options: [], metrics: nil, views: ["detailLabelContainer": detailLabelContainer!])
verticalFormat += "[detailLabelContainer]"
views["detailLabelContainer"] = detailLabelContainer!
if 0 == maximumDetailLabelHeight {
Layout.expandToParentWithPad(detailLabelContainer!, child: detailLabel!, top: detailLabelTopInset, left: detailLabelLeftInset, bottom: detailLabelBottomInset, right: detailLabelRightInset)
} else {
Layout.expandToParentHorizontallyWithPad(detailLabelContainer!, child: detailLabel!, left: detailLabelLeftInset, right: detailLabelRightInset)
detailLabelContainer!.addConstraints(Layout.constraint("V:|-(detailLabelTopInset)-[detailLabel(<=maximumDetailLabelHeight)]-(detailLabelBottomInset)-|", options: [], metrics: ["detailLabelTopInset": detailLabelTopInset, "detailLabelBottomInset": detailLabelBottomInset, "maximumDetailLabelHeight": maximumDetailLabelHeight], views: ["detailLabel": detailLabel!]))
}
}
// buttons
if nil != leftButtons || nil != rightButtons {
// clear for updated constraints
buttonsContainer!.removeConstraints(buttonsContainer!.constraints)
// divider
if nil != divider {
layoutConstraints += Layout.constraint("H:|[divider]|", options: [], metrics: nil, views: ["divider": divider!])
views["divider"] = divider!
verticalFormat += "[divider(1)]"
}
//container
layoutConstraints += Layout.constraint("H:|[buttonsContainer]|", options: [], metrics: nil, views: ["buttonsContainer": buttonsContainer!])
verticalFormat += "[buttonsContainer]"
views["buttonsContainer"] = buttonsContainer!
// leftButtons
if nil != leftButtons {
var horizontalFormat: String = "H:|"
var buttonViews: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
for var i: Int = 0, l: Int = leftButtons!.count; i < l; ++i {
let button: MaterialButton = leftButtons![i]
buttonsContainer!.addSubview(button)
buttonViews["button\(i)"] = button
horizontalFormat += "-(buttonLeftInset)-[button\(i)]"
Layout.expandToParentVerticallyWithPad(buttonsContainer!, child: button, top: buttonTopInset, bottom: buttonBottomInset)
}
buttonsContainer!.addConstraints(Layout.constraint(horizontalFormat, options: [], metrics: ["buttonLeftInset": buttonLeftInset], views: buttonViews))
}
// rightButtons
if nil != rightButtons {
var horizontalFormat: String = "H:"
var buttonViews: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
for var i: Int = 0, l: Int = rightButtons!.count; i < l; ++i {
let button: MaterialButton = rightButtons![i]
buttonsContainer!.addSubview(button)
buttonViews["button\(i)"] = button
horizontalFormat += "[button\(i)]-(buttonRightInset)-"
Layout.expandToParentVerticallyWithPad(buttonsContainer!, child: button, top: buttonTopInset, bottom: buttonBottomInset)
}
buttonsContainer!.addConstraints(Layout.constraint(horizontalFormat + "|", options: [], metrics: ["buttonRightInset": buttonRightInset], views: buttonViews))
}
}
verticalFormat += "|"
// combine constraints
if 0 < layoutConstraints.count {
layoutConstraints += Layout.constraint(verticalFormat, options: [], metrics: nil, views: views)
NSLayoutConstraint.activateConstraints(layoutConstraints)
}
}
//
// :name: prepareProperties
//
internal func prepareProperties(titleLabel: UILabel?, detailLabel: UILabel?, divider: UIView?, leftButtons: Array<MaterialButton>?, rightButtons: Array<MaterialButton>?) {
self.titleLabel = titleLabel
self.detailLabel = detailLabel
self.divider = divider
self.leftButtons = leftButtons
self.rightButtons = rightButtons
}
//
// :name: prepareView
//
internal override func prepareView() {
super.prepareView()
prepareShadow()
backgroundColor = MaterialTheme.color.blueGrey.base
}
}
public func <=(lhs: BasicCardView, rhs: BasicCardView) -> Bool {
return lhs.tag <= rhs.tag
}
public func >=(lhs: BasicCardView, rhs: BasicCardView) -> Bool {
return lhs.tag >= rhs.tag
}
public func >(lhs: BasicCardView, rhs: BasicCardView) -> Bool {
return lhs.tag > rhs.tag
}
public func <(lhs: BasicCardView, rhs: BasicCardView) -> Bool {
return lhs.tag < rhs.tag
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import AVFoundation
import AssetsLibrary
@objc(CaptureDelegate)
public protocol CaptureDelegate {
optional func captureDeviceConfigurationFailed(capture: Capture, error: NSError!)
optional func captureMediaCaptureFailed(capture: Capture, error: NSError!)
optional func captureAsetLibraryWriteFailed(capture: Capture, error: NSError!)
optional func capture(capture: Capture, assetLibraryDidWrite image: UIImage!)
}
public class Capture: NSObject, AVCaptureFileOutputRecordingDelegate {
//
// :name: activeVideoInput
// :description: The video input that is currently active.
//
private var activeVideoInput: AVCaptureDeviceInput?
//
// :name: imageOutput
// :description: When the session is taking a photo, this is the output manager.
//
private lazy var imageOutput: AVCaptureStillImageOutput = AVCaptureStillImageOutput()
//
// :name: movieOutput
// :description: When the session is shooting a video, this is the output manager.
//
private lazy var movieOutput: AVCaptureMovieFileOutput = AVCaptureMovieFileOutput()
//
// :name: movieOutputURL
// :description: The output URL of the movie file.
//
private var movieOutputURL: NSURL?
//
// :name: queue
// :description: Async job queue.
//
private lazy var queue: dispatch_queue_t = {
return dispatch_queue_create("io.graphkit.Capture", nil)
}()
//
// :name: CaptureAdjustingExposureContext
// :description: Used for KVO observation context.
//
public var CaptureAdjustingExposureContext: NSString?
/**
* cameraCount
* The number of available cameras on the device.
*/
public var cameraCount: Int {
return AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo).count
}
/**
* session
* An AVCaptureSession that manages all inputs and outputs in that session.
*/
public lazy var session: AVCaptureSession = AVCaptureSession()
/**
* delegate
* An optional instance of CaptureDelegate to handle events that are triggered during various
* stages in the session.
*/
public weak var delegate: CaptureDelegate?
/**
* prepareSession
* A helper method that prepares the session with the various available inputs and outputs.
* @param preset: String, default: AVCaptureSessionPresetHigh
* @return A boolean value, true if successful, false otherwise.
*/
public func prepareSession(preset: String = AVCaptureSessionPresetHigh) -> Bool {
session.sessionPreset = preset
// setup default camera device
let videoDevice: AVCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
let videoInput: AVCaptureDeviceInput? = try? AVCaptureDeviceInput(device: videoDevice)
if nil == videoInput {
return false
}
if session.canAddInput(videoInput) {
session.addInput(videoInput)
activeVideoInput = videoInput
}
let audioDevice: AVCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeAudio)
let audioInput: AVCaptureDeviceInput? = try? AVCaptureDeviceInput(device: audioDevice)
if nil == audioInput {
return false
}
if session.canAddInput(audioInput) {
session.addInput(audioInput)
}
imageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
if session.canAddOutput(imageOutput) {
session.addOutput(imageOutput)
}
if session.canAddOutput(movieOutput) {
session.addOutput(movieOutput)
}
return true
}
/**
* startSession
* Starts the capture session if it is not already running.
*/
public func startSession() {
if !session.running {
dispatch_async(queue) {
self.session.startRunning()
}
}
}
/**
* stopSession
* Stops the capture session if it is already running.
*/
public func stopSession() {
if session.running {
dispatch_async(queue) {
self.session.stopRunning()
}
}
}
/**
* cameraWithPosition
* @param position: AVCaptureDevicePosition
* @return An AVCaptureDevice optional.
*/
public func cameraWithPosition(position: AVCaptureDevicePosition) -> AVCaptureDevice? {
for device in AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) {
if position == device.position {
return device as? AVCaptureDevice
}
}
return nil
}
/**
* activeCamera
* @return The active cameras video input device.
*/
public var activeCamera: AVCaptureDevice {
get {
return activeVideoInput!.device
}
}
/**
* inactiveCamera
* @return The inactive cameras video input device.
*/
public var inactiveCamera: AVCaptureDevice? {
get {
var device: AVCaptureDevice?
if 1 < cameraCount {
device = activeCamera.position == .Back ? cameraWithPosition(.Front) : cameraWithPosition(.Back)
}
return device
}
}
/**
* canSwitchCameras
* Checks whether the camera can be switched. This would require at least two cameras.
* @return A boolean of the result, true if yes, false otherwise.
*/
public var canSwitchCameras: Bool {
return 1 < cameraCount
}
/**
* switchCamera
* If it is possible to switch cameras, then the camera will be switched from the opposite facing camera.
* @return A boolean of the result, true if switched, false otherwise.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public func switchCamera() -> Bool {
if !canSwitchCameras {
return false
}
let videoDevice: AVCaptureDevice? = inactiveCamera
let videoInput: AVCaptureDeviceInput? = try? AVCaptureDeviceInput(device: videoDevice)
if nil == videoInput {
session.beginConfiguration()
session.removeInput(activeVideoInput)
if session.canAddInput(videoInput) {
activeVideoInput = videoInput
} else {
session.addInput(activeVideoInput)
}
session.commitConfiguration()
} else {
delegate?.captureDeviceConfigurationFailed?(self, error: nil)
return false
}
return true
}
/**
* cameraHasFlash
* Checks whether the camera supports flash.
* @return A boolean of the result, true if yes, false otherwise.
*/
public var cameraHasFlash: Bool {
return activeCamera.hasFlash
}
/**
* flashMode
* A mutator and accessor for the flashMode property.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public var flashMode: AVCaptureFlashMode {
get {
return activeCamera.flashMode
}
set(value) {
let device: AVCaptureDevice = activeCamera
if flashMode != device.flashMode && device.isFlashModeSupported(flashMode) {
var error: NSError?
do {
try device.lockForConfiguration()
device.flashMode = flashMode
device.unlockForConfiguration()
} catch let error1 as NSError {
error = error1
delegate?.captureDeviceConfigurationFailed?(self, error: error)
}
}
}
}
/**
* cameraHasTorch
* Checks whether the device supports torch feature.
* @return A boolean of the result, true if yes, false otherwise.
*/
public var cameraHasTorch: Bool {
get {
return activeCamera.hasTorch
}
}
/**
* torchMode
* A mutator and accessor for the torchMode property.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public var torchMode: AVCaptureTorchMode {
get {
return activeCamera.torchMode
}
set(value) {
let device: AVCaptureDevice = activeCamera
if torchMode != device.torchMode && device.isTorchModeSupported(torchMode) {
var error: NSError?
do {
try device.lockForConfiguration()
device.torchMode = torchMode
device.unlockForConfiguration()
} catch let error1 as NSError {
error = error1
delegate?.captureDeviceConfigurationFailed?(self, error: error)
}
}
}
}
/**
* cameraSupportsTapToFocus
* Checks whether the device supports tap to focus.
* @return A boolean of the result, true if yes, false otherwise.
*/
public var cameraSupportsTapToFocus: Bool {
get {
return activeCamera.focusPointOfInterestSupported
}
}
/**
* focusAtpoint
* Sets the point to focus at on the screen.
* @param point: CGPoint
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public func focusAtPoint(point: CGPoint) {
let device: AVCaptureDevice = activeCamera
if device.focusPointOfInterestSupported && device.isFocusModeSupported(.AutoFocus) {
var error: NSError?
do {
try device.lockForConfiguration()
device.focusPointOfInterest = point
device.focusMode = .AutoFocus
device.unlockForConfiguration()
} catch let error1 as NSError {
error = error1
delegate?.captureDeviceConfigurationFailed?(self, error: error)
}
}
}
/**
* cameraSupportsTapToExpose
* Checks whether the device supports tap to expose.
* @return A boolean of the result, true if yes, false otherwise.
*/
public var cameraSupportsTapToExpose: Bool {
get {
return activeCamera.exposurePointOfInterestSupported
}
}
/**
* exposeAtPoint
* Sets a point for exposure.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public func exposeAtPoint(point: CGPoint) {
let device: AVCaptureDevice = activeCamera
let exposureMode: AVCaptureExposureMode = .ContinuousAutoExposure
if device.exposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) {
var error: NSError?
do {
try device.lockForConfiguration()
device.exposurePointOfInterest = point
device.exposureMode = exposureMode
if device.isExposureModeSupported(.Locked) {
device.addObserver(self, forKeyPath: "adjustingExposure", options: .New, context: &CaptureAdjustingExposureContext)
}
device.unlockForConfiguration()
} catch let error1 as NSError {
error = error1
delegate?.captureDeviceConfigurationFailed?(self, error: error)
}
}
}
/**
* override to set observeValueForKeyPath and handle exposure observance.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if context == &CaptureAdjustingExposureContext {
let device: AVCaptureDevice = object as! AVCaptureDevice
if device.adjustingExposure && device.isExposureModeSupported(.Locked) {
object!.removeObserver(self, forKeyPath: "adjustingExposure", context: &CaptureAdjustingExposureContext)
dispatch_async(queue) {
var error: NSError?
do {
try device.lockForConfiguration()
device.unlockForConfiguration()
} catch let e as NSError {
error = e
self.delegate?.captureDeviceConfigurationFailed?(self, error: error)
} catch {
fatalError()
}
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
}
/**
* resetFocusAndExposureModes
* Resets to default configuration for device focus and exposure mode.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public func resetFocusAndExposureModes() {
let device: AVCaptureDevice = activeCamera
let exposureMode: AVCaptureExposureMode = .ContinuousAutoExposure
let canResetExposure: Bool = device.focusPointOfInterestSupported && device.isExposureModeSupported(exposureMode)
let focusMode: AVCaptureFocusMode = .ContinuousAutoFocus
let canResetFocus: Bool = device.focusPointOfInterestSupported && device.isFocusModeSupported(focusMode)
let centerPoint: CGPoint = CGPointMake(0.5, 0.5)
var error: NSError?
do {
try device.lockForConfiguration()
if canResetFocus {
device.focusMode = focusMode
device.focusPointOfInterest = centerPoint
}
if canResetExposure {
device.exposureMode = exposureMode
device.exposurePointOfInterest = centerPoint
}
device.unlockForConfiguration()
} catch let error1 as NSError {
error = error1
delegate?.captureDeviceConfigurationFailed?(self, error: error)
}
}
/**
* captureStillImage
* Captures the image and write the photo to the user's asset library.
* @delegate If the success, the capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) is called.
* @delegate If failure, capture(capture: Capture!, assetLibraryWriteFailed error: NSError!) is called.
*/
public func captureStillImage() {
let connection: AVCaptureConnection = imageOutput.connectionWithMediaType(AVMediaTypeVideo)
if connection.supportsVideoOrientation {
connection.videoOrientation = currentVideoOrientation
}
imageOutput.captureStillImageAsynchronouslyFromConnection(connection) { (sampleBuffer: CMSampleBufferRef?, error: NSError?) in
if nil == sampleBuffer {
self.delegate?.captureAsetLibraryWriteFailed?(self, error: error)
} else {
let imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
let image: UIImage = UIImage(data: imageData)!
self.writeImageToAssetsLibrary(image)
}
}
}
/**
* isRecording
* Checkts whether the device is currently recording.
* @return A boolean of the result, true if yes, false otherwise.
*/
public var isRecording: Bool {
get {
return movieOutput.recording
}
}
/**
* startRecording
* If the device is not currently recording, this starts the movie recording.
* @delegate If the configuration fails, the capture(capture: Capture!, deviceConfigurationFailed error: NSError!) is called.
*/
public func startRecording() {
if !isRecording {
let connection: AVCaptureConnection = movieOutput.connectionWithMediaType(AVMediaTypeVideo)
if connection.supportsVideoOrientation {
connection.videoOrientation = currentVideoOrientation
}
if connection.supportsVideoStabilization {
connection.preferredVideoStabilizationMode = .Auto
}
let device: AVCaptureDevice = activeCamera
if device.smoothAutoFocusSupported {
var error: NSError?
do {
try device.lockForConfiguration()
device.smoothAutoFocusEnabled = false
device.unlockForConfiguration()
} catch let error1 as NSError {
error = error1
delegate?.captureDeviceConfigurationFailed?(self, error: error)
}
}
movieOutputURL = uniqueURL
movieOutput.startRecordingToOutputFileURL(movieOutputURL, recordingDelegate: self)
}
}
/**
* stopRecording
* If the device is currently recoring, this stops the movie recording.
*/
public func stopRecording() {
if isRecording {
movieOutput.stopRecording()
}
}
/**
* recordedDuration
* Retrieves the movie recorded duration.
* @return A CMTime value.
*/
public var recordedDuration: CMTime {
get {
return movieOutput.recordedDuration
}
}
/**
* currentVideoOrientation
* Retrieves the current orientation of the device.
* @return A AVCaptureVideoOrientation value, [Portrait, LandscapeLeft, PortraitUpsideDown, LandscapeRight].
*/
public var currentVideoOrientation: AVCaptureVideoOrientation {
var orientation: AVCaptureVideoOrientation?
switch UIDevice.currentDevice().orientation {
case .Portrait:
orientation = .Portrait
break
case .LandscapeRight:
orientation = .LandscapeLeft
break
case .PortraitUpsideDown:
orientation = .PortraitUpsideDown
break
default:
orientation = .LandscapeRight
}
return orientation!
}
/**
* uniqueURL
* A unique URL generated for the movie video.
* @return An optional NSURL value.
*/
private var uniqueURL: NSURL? {
let fileManager: NSFileManager = NSFileManager.defaultManager()
let tempDirectoryTemplate: String = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("FocusLibrary")
do {
try fileManager.createDirectoryAtPath(tempDirectoryTemplate, withIntermediateDirectories: true, attributes: nil)
return NSURL.fileURLWithPath(tempDirectoryTemplate + "/test.mov")
} catch {}
return nil
}
/**
* postAssetLibraryNotification
* Fires an asynchronous call to the capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) delegate.
* @param image: UIImage!
* @delegate An asynchronous call to capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) delegate.
*/
private func postAssetLibraryNotification(image: UIImage!) {
dispatch_async(queue) {
self.delegate?.capture?(self, assetLibraryDidWrite: image)
}
}
/**
* writeImageToAssetsLibrary
* Writes the image file to the user's asset library.
* @param image: UIImage!
* @delegate If successful, an asynchronous call to capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) delegate.
* @delegate If failure, capture(capture: Capture!, assetLibraryWriteFailed error: NSError!) is called.
*/
private func writeImageToAssetsLibrary(image: UIImage) {
let library: ALAssetsLibrary = ALAssetsLibrary()
library.writeImageToSavedPhotosAlbum(image.CGImage, orientation: ALAssetOrientation(rawValue: image.imageOrientation.rawValue)!) { (path: NSURL!, error: NSError?) -> Void in
if nil == error {
self.postAssetLibraryNotification(image)
} else {
self.delegate?.captureAsetLibraryWriteFailed?(self, error: error)
}
}
}
/**
* writeVideoToAssetsLibrary
* Writes the video file to the user's asset library.
* @param videoURL: NSURL!
* @delegate If successful, an asynchronous call to capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) delegate.
* @delegate If failure, capture(capture: Capture!, assetLibraryWriteFailed error: NSError!) is called.
*/
private func writeVideoToAssetsLibrary(videoURL: NSURL!) {
let library: ALAssetsLibrary = ALAssetsLibrary()
if library.videoAtPathIsCompatibleWithSavedPhotosAlbum(videoURL) {
library.writeVideoAtPathToSavedPhotosAlbum(videoURL) { (path: NSURL!, error: NSError?) in
if nil == error {
self.generateThumbnailForVideoAtURL(videoURL)
} else {
self.delegate?.captureAsetLibraryWriteFailed?(self, error: error)
}
}
}
}
/**
* generateThumbnailForVideoAtURL
* Generates a thumbnail for the video URL specified.
* @param videoURL: NSURL!
* @delegate An asynchronous call to capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) delegate.
*/
private func generateThumbnailForVideoAtURL(videoURL: NSURL!) {
dispatch_async(queue) {
do {
let asset: AVAsset = AVAsset(URL: videoURL)
let imageGenerator: AVAssetImageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.maximumSize = CGSizeMake(100, 0)
imageGenerator.appliesPreferredTrackTransform = true
let imageRef: CGImageRef = try imageGenerator.copyCGImageAtTime(kCMTimeZero, actualTime: nil)
let image: UIImage = UIImage(CGImage: imageRef)
dispatch_async(dispatch_get_main_queue()) {
self.postAssetLibraryNotification(image)
}
} catch {}
}
}
/**
* delegate method for capturing video file.
* @delegate If successful, an asynchronous call to capture(capture: Capture!, assetLibraryDidWrite image: UIImage!) delegate.
* @delegate If failure, capture(capture: Capture!, mediaCaptureFailed error: NSError!) is called.
*/
public func captureOutput(captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAtURL outputFileURL: NSURL!, fromConnections connections: [AnyObject]!, error: NSError!) {
if nil == error {
writeVideoToAssetsLibrary(movieOutputURL!.copy() as! NSURL)
} else {
delegate?.captureMediaCaptureFailed?(self, error: error)
}
movieOutputURL = nil
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import AVFoundation
@objc(PreviewDelegate)
public protocol PreviewDelegate {
optional func previewTappedToFocusAt(preview: Preview, point: CGPoint)
optional func previewTappedToExposeAt(preview: Preview, point: CGPoint)
optional func previewTappedToReset(preview: Preview, focus: UIView, exposure: UIView)
}
public class Preview: UIView {
/**
:name: boxBounds
:description: A static property that sets the initial size of the focusBox and exposureBox properties.
*/
static public var boxBounds: CGRect = CGRectMake(0, 0, 150, 150)
/**
:name: delegate
:description: An optional instance of PreviewDelegate to handle events that are triggered during various
stages of engagement.
*/
public weak var delegate: PreviewDelegate?
/**
:name: tapToFocusEnabled
:description: A mutator and accessor that enables and disables tap to focus gesture.
*/
public var tapToFocusEnabled: Bool {
get {
return singleTapRecognizer!.enabled
}
set(value) {
singleTapRecognizer!.enabled = value
}
}
/**
:name: tapToExposeEnabled
:description: A mutator and accessor that enables and disables tap to expose gesture.
*/
public var tapToExposeEnabled: Bool {
get {
return doubleTapRecognizer!.enabled
}
set(value) {
doubleTapRecognizer!.enabled = value
}
}
//
// override for layerClass
//
override public class func layerClass() -> AnyClass {
return AVCaptureVideoPreviewLayer.self
}
/**
:name: session
:description: A mutator and accessor for the preview AVCaptureSession value.
*/
public var session: AVCaptureSession {
get {
return (layer as! AVCaptureVideoPreviewLayer).session
}
set(value) {
(layer as! AVCaptureVideoPreviewLayer).session = value
}
}
/**
:name: focusBox
:description: An optional UIView for the focusBox animation. This is used when the
tapToFocusEnabled property is set to true.
*/
public var focusBox: UIView?
/**
:name: exposureBox
:description: An optional UIView for the exposureBox animation. This is used when the
tapToExposeEnabled property is set to true.
*/
public var exposureBox: UIView?
//
// :name: singleTapRecognizer
// :description: Gesture recognizer for single tap.
//
private var singleTapRecognizer: UITapGestureRecognizer?
//
// :name: doubleTapRecognizer
// :description: Gesture recognizer for double tap.
//
private var doubleTapRecognizer: UITapGestureRecognizer?
//
// :name: doubleDoubleTapRecognizer
// :description: Gesture recognizer for double/double tap.
//
private var doubleDoubleTapRecognizer: UITapGestureRecognizer?
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
public override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
public init() {
super.init(frame: CGRectZero)
translatesAutoresizingMaskIntoConstraints = false
prepareView()
}
//
// :name: handleSingleTap
//
internal func handleSingleTap(recognizer: UIGestureRecognizer) {
let point: CGPoint = recognizer.locationInView(self)
runBoxAnimationOnView(focusBox, point: point)
delegate?.previewTappedToFocusAt?(self, point: captureDevicePointForPoint(point))
}
//
// :name: handleDoubleTap
//
internal func handleDoubleTap(recognizer: UIGestureRecognizer) {
let point: CGPoint = recognizer.locationInView(self)
runBoxAnimationOnView(exposureBox, point: point)
delegate?.previewTappedToExposeAt?(self, point: captureDevicePointForPoint(point))
}
//
// :name: handleDoubleDoubleTap
//
internal func handleDoubleDoubleTap(recognizer: UIGestureRecognizer) {
runResetAnimation()
}
//
// :name: prepareView
// :description: Common setup for view.
//
private func prepareView() {
let captureLayer: AVCaptureVideoPreviewLayer = layer as! AVCaptureVideoPreviewLayer
captureLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
singleTapRecognizer = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
singleTapRecognizer!.numberOfTapsRequired = 1
doubleTapRecognizer = UITapGestureRecognizer(target: self, action: "handleDoubleTap:")
doubleTapRecognizer!.numberOfTapsRequired = 2
doubleDoubleTapRecognizer = UITapGestureRecognizer(target: self, action: "handleDoubleDoubleTap:")
doubleDoubleTapRecognizer!.numberOfTapsRequired = 2
doubleDoubleTapRecognizer!.numberOfTouchesRequired = 2
addGestureRecognizer(singleTapRecognizer!)
addGestureRecognizer(doubleTapRecognizer!)
addGestureRecognizer(doubleDoubleTapRecognizer!)
singleTapRecognizer!.requireGestureRecognizerToFail(doubleTapRecognizer!)
focusBox = viewWithColor(.redColor())
exposureBox = viewWithColor(.blueColor())
addSubview(focusBox!)
addSubview(exposureBox!)
}
//
// :name: viewWithColor
// :description: Initializes a UIView with a set UIColor.
//
private func viewWithColor(color: UIColor) -> UIView {
let view: UIView = UIView(frame: Preview.boxBounds)
view.backgroundColor = MaterialTheme.color.clear.base
view.layer.borderColor = color.CGColor
view.layer.borderWidth = 5
view.hidden = true
return view
}
//
// :name: runBoxAnimationOnView
// :description: Runs the animation used for focusBox and exposureBox on single and double
// taps respectively at a given point.
//
private func runBoxAnimationOnView(view: UIView!, point: CGPoint) {
view.center = point
view.hidden = false
UIView.animateWithDuration(0.15, delay: 0, options: .CurveEaseInOut, animations: { _ in
view.layer.transform = CATransform3DMakeScale(0.5, 0.5, 1)
}) { _ in
let delayInSeconds: Double = 0.5
let popTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
dispatch_after(popTime, dispatch_get_main_queue()) {
view.hidden = true
view.transform = CGAffineTransformIdentity
}
}
}
//
// :name: captureDevicePointForPoint
// :description: Interprets the correct point from touch to preview layer.
//
private func captureDevicePointForPoint(point: CGPoint) -> CGPoint {
let previewLayer: AVCaptureVideoPreviewLayer = layer as! AVCaptureVideoPreviewLayer
return previewLayer.captureDevicePointOfInterestForPoint(point)
}
//
// :name: runResetAnimation
// :description: Executes the reset animation for focus and exposure.
//
private func runResetAnimation() {
if !tapToFocusEnabled && !tapToExposeEnabled {
return
}
let previewLayer: AVCaptureVideoPreviewLayer = layer as! AVCaptureVideoPreviewLayer
let centerPoint: CGPoint = previewLayer.pointForCaptureDevicePointOfInterest(CGPointMake(0.5, 0.5))
focusBox!.center = centerPoint
exposureBox!.center = centerPoint
exposureBox!.transform = CGAffineTransformMakeScale(1.2, 1.2)
focusBox!.hidden = false
exposureBox!.hidden = false
UIView.animateWithDuration(0.15, delay: 0, options: .CurveEaseInOut, animations: { _ in
self.focusBox!.layer.transform = CATransform3DMakeScale(0.5, 0.5, 1)
self.exposureBox!.layer.transform = CATransform3DMakeScale(0.7, 0.7, 1)
}) { _ in
let delayInSeconds: Double = 0.5
let popTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
dispatch_after(popTime, dispatch_get_main_queue()) {
self.focusBox!.hidden = true
self.exposureBox!.hidden = true
self.focusBox!.transform = CGAffineTransformIdentity
self.exposureBox!.transform = CGAffineTransformIdentity
self.delegate?.previewTappedToReset?(self, focus: self.focusBox!, exposure: self.exposureBox!)
}
}
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class FabButton : MaterialButton {
//
// :name: prepareButton
//
internal override func prepareView() {
super.prepareView()
setTitleColor(MaterialTheme.color.white.base, forState: .Normal)
backgroundColor = MaterialTheme.color.red.darken1
contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0)
}
//
// :name: prepareButton
//
internal override func prepareButton() {
super.prepareButton()
prepareShadow()
backgroundColorView.layer.cornerRadius = bounds.width / 2
}
//
// :name: pulseBegan
//
internal override func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
super.pulseBegan(touches, withEvent: event)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(3, 3)
self.transform = CGAffineTransformMakeScale(1.1, 1.1)
})
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class FlatButton : MaterialButton {
//
// :name: prepareView
//
internal override func prepareView() {
super.prepareView()
titleLabel!.font = Roboto.regular
setTitleColor(MaterialTheme.color.blueGrey.darken4, forState: .Normal)
pulseColor = MaterialTheme.color.blueGrey.lighten3
backgroundColor = MaterialTheme.color.clear.base
contentEdgeInsets = UIEdgeInsetsMake(MaterialTheme.buttonVerticalInset, MaterialTheme.buttonHorizontalInset, MaterialTheme.buttonVerticalInset, MaterialTheme.buttonHorizontalInset)
}
//
// :name: prepareButton
//
internal override func prepareButton() {
super.prepareButton()
backgroundColorView.layer.cornerRadius = 3
}
//
// :name: pulseBegan
//
internal override func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
super.pulseBegan(touches, withEvent: event)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(4, 4)
self.transform = CGAffineTransformMakeScale(1.05, 1.05)
})
}
}
//
// Copyright (C) 1615 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class ImageCardView : MaterialCardView, Comparable {
//
// :name: layoutConstraints
//
internal lazy var layoutConstraints: Array<NSLayoutConstraint> = Array<NSLayoutConstraint>()
/**
:name: imageViewVerticalInset
*/
public var imageViewVerticalInset: CGFloat = 0 {
didSet {
imageViewTopInset = imageViewVerticalInset
imageViewBottomInset = imageViewVerticalInset
}
}
/**
:name: imageViewTopInset
*/
public var imageViewTopInset: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: imageViewBottomInset
*/
public var imageViewBottomInset: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: imageViewHorizontalInset
*/
public var imageViewHorizontalInset: CGFloat = 0 {
didSet {
imageViewLeftInset = imageViewHorizontalInset
imageViewRightInset = imageViewHorizontalInset
}
}
/**
:name: imageViewLeftInset
*/
public var imageViewLeftInset: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: imageViewRightInset
*/
public var imageViewRightInset: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: titleLabelVerticalInset
*/
public var titleLabelVerticalInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
titleLabelTopInset = titleLabelVerticalInset
titleLabelBottomInset = titleLabelVerticalInset
}
}
/**
:name: titleLabelTopInset
*/
public var titleLabelTopInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: titleLabelBottomInset
*/
public var titleLabelBottomInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: titleLabelHorizontalInset
*/
public var titleLabelHorizontalInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
titleLabelLeftInset = titleLabelHorizontalInset
titleLabelRightInset = titleLabelHorizontalInset
}
}
/**
:name: titleLabelLeftInset
*/
public var titleLabelLeftInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: titleLabelRightInset
*/
public var titleLabelRightInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelVerticalInset
*/
public var detailLabelVerticalInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
detailLabelTopInset = detailLabelVerticalInset
detailLabelBottomInset = detailLabelVerticalInset
}
}
/**
:name: detailLabelTopInset
*/
public var detailLabelTopInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelBottomInset
*/
public var detailLabelBottomInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelHorizontalInset
*/
public var detailLabelHorizontalInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
detailLabelLeftInset = detailLabelHorizontalInset
detailLabelRightInset = detailLabelHorizontalInset
}
}
/**
:name: detailLabelLeftInset
*/
public var detailLabelLeftInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: detailLabelRightInset
*/
public var detailLabelRightInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
reloadView()
}
}
/**
:name: buttonVerticalInset
*/
public var buttonVerticalInset: CGFloat = MaterialTheme.cardVerticalInset {
didSet {
buttonTopInset = buttonVerticalInset
buttonBottomInset = buttonVerticalInset
}
}
/**
:name: buttonTopInset
*/
public var buttonTopInset: CGFloat = MaterialTheme.cardVerticalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: buttonBottomInset
*/
public var buttonBottomInset: CGFloat = MaterialTheme.cardVerticalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: buttonHorizontalInset
*/
public var buttonHorizontalInset: CGFloat = MaterialTheme.cardHorizontalInset {
didSet {
buttonLeftInset = buttonHorizontalInset
buttonRightInset = buttonHorizontalInset
}
}
/**
:name: buttonLeftInset
*/
public var buttonLeftInset: CGFloat = MaterialTheme.cardHorizontalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: buttonRightInset
*/
public var buttonRightInset: CGFloat = MaterialTheme.cardHorizontalInset / 2 {
didSet {
reloadView()
}
}
/**
:name: shadow
*/
public var shadow: Bool = true {
didSet {
false == shadow ? removeShadow() : prepareShadow()
reloadView()
}
}
/**
:name: maximumImageViewHeight
*/
public var maximumImageViewHeight: CGFloat = 200 {
didSet {
reloadView()
}
}
/**
:name: imageViewContainer
*/
public private(set) var imageViewContainer: UIView?
/**
:name: imageView
*/
public var imageView: UIImageView? {
didSet {
if let t = imageView {
// container
if nil == imageViewContainer {
imageViewContainer = UIView()
imageViewContainer!.translatesAutoresizingMaskIntoConstraints = false
imageViewContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(imageViewContainer!)
}
// text
imageViewContainer!.addSubview(t)
t.translatesAutoresizingMaskIntoConstraints = false
t.contentMode = .ScaleAspectFill
t.userInteractionEnabled = false
t.clipsToBounds = true
if nil != titleLabel {
titleLabelContainer!.backgroundColor = MaterialTheme.color.clear.base
titleLabel!.textColor = MaterialTheme.color.white.base
titleLabelContainer!.removeFromSuperview()
imageViewContainer!.addSubview(titleLabelContainer!)
}
} else {
imageViewContainer?.removeFromSuperview()
imageViewContainer = nil
}
reloadView()
}
}
/**
:name: maximumTitleLabelHeight
*/
public var maximumTitleLabelHeight: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: titleLabelContainer
*/
public private(set) var titleLabelContainer: UIView?
/**
:name: titleLabel
*/
public var titleLabel: UILabel? {
didSet {
if let t = titleLabel {
// container
if nil == titleLabelContainer {
titleLabelContainer = UIView()
titleLabelContainer!.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLabelContainer!)
}
// text
titleLabelContainer!.addSubview(t)
t.translatesAutoresizingMaskIntoConstraints = false
t.backgroundColor = MaterialTheme.color.clear.base
t.font = Roboto.regular
t.numberOfLines = 0
t.lineBreakMode = .ByTruncatingTail
if nil == imageView {
titleLabelContainer!.backgroundColor = MaterialTheme.color.clear.base
t.textColor = MaterialTheme.color.black.base
} else {
titleLabelContainer!.backgroundColor = MaterialTheme.color.clear.base
t.textColor = MaterialTheme.color.clear.base
titleLabelContainer!.removeFromSuperview()
imageViewContainer!.addSubview(titleLabelContainer!)
}
} else {
titleLabelContainer?.removeFromSuperview()
titleLabelContainer = nil
}
reloadView()
}
}
/**
:name: maximumDetailLabelHeight
*/
public var maximumDetailLabelHeight: CGFloat = 0 {
didSet {
reloadView()
}
}
/**
:name: detailLabelContainer
*/
public private(set) var detailLabelContainer: UIView?
/**
:name: detailLabel
*/
public var detailLabel: UILabel? {
didSet {
if let l = detailLabel {
// container
if nil == detailLabelContainer {
detailLabelContainer = UIView()
detailLabelContainer!.translatesAutoresizingMaskIntoConstraints = false
detailLabelContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(detailLabelContainer!)
}
// text
detailLabelContainer!.addSubview(l)
l.translatesAutoresizingMaskIntoConstraints = false
l.textColor = MaterialTheme.color.black.base
l.backgroundColor = MaterialTheme.color.clear.base
l.font = Roboto.light
l.numberOfLines = 0
l.lineBreakMode = .ByTruncatingTail
} else {
detailLabelContainer?.removeFromSuperview()
detailLabelContainer = nil
}
reloadView()
}
}
/**
:name: divider
*/
public var divider: UIView? {
didSet {
if let d = divider {
d.translatesAutoresizingMaskIntoConstraints = false
d.backgroundColor = MaterialTheme.color.blueGrey.lighten5
addSubview(d)
} else {
divider?.removeFromSuperview()
}
reloadView()
}
}
/**
:name: buttonsContainer
*/
public private(set) var buttonsContainer: UIView?
/**
:name: leftButtons
*/
public var leftButtons: Array<MaterialButton>? {
didSet {
if nil == rightButtons && nil == leftButtons {
buttonsContainer?.removeFromSuperview()
buttonsContainer = nil
} else if nil == buttonsContainer {
buttonsContainer = UIView()
buttonsContainer!.translatesAutoresizingMaskIntoConstraints = false
buttonsContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(buttonsContainer!)
}
reloadView()
}
}
/**
:name: rightButtons
*/
public var rightButtons: Array<MaterialButton>? {
didSet {
if nil == rightButtons && nil == leftButtons {
buttonsContainer?.removeFromSuperview()
buttonsContainer = nil
} else if nil == buttonsContainer {
buttonsContainer = UIView()
buttonsContainer!.translatesAutoresizingMaskIntoConstraints = false
buttonsContainer!.backgroundColor = MaterialTheme.color.clear.base
addSubview(buttonsContainer!)
} else {
for v in buttonsContainer!.subviews {
v.removeFromSuperview()
}
}
reloadView()
}
}
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public convenience init?(imageView: UIImageView? = nil, titleLabel: UILabel? = nil, detailLabel: UILabel? = nil, divider: UIView? = nil, leftButtons: Array<MaterialButton>? = nil, rightButtons: Array<MaterialButton>? = nil) {
self.init(frame: CGRectZero)
prepareProperties(imageView, titleLabel: titleLabel, detailLabel: detailLabel, divider: divider, leftButtons: leftButtons, rightButtons: rightButtons)
}
/**
:name: init
*/
public required init(frame: CGRect) {
super.init(frame: frame)
}
/**
:name: isEqual
*/
public override func isEqual(object: AnyObject?) -> Bool {
if let rhs = object as? ImageCardView {
return tag == rhs.tag
}
return false
}
/**
:name: reloadView
*/
public func reloadView() {
// clear all constraints
NSLayoutConstraint.deactivateConstraints(layoutConstraints)
layoutConstraints.removeAll(keepCapacity: false)
// detect all components and create constraints
var verticalFormat: String = "V:|"
var views: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
// image
if nil != imageView {
// clear for updated constraints
imageViewContainer!.removeConstraints(imageViewContainer!.constraints)
// container
layoutConstraints += Layout.constraint("H:|[imageViewContainer]|", options: [], metrics: nil, views: ["imageViewContainer": imageViewContainer!])
verticalFormat += "[imageViewContainer]"
views["imageViewContainer"] = imageViewContainer!
// text
Layout.expandToParentHorizontallyWithPad(imageViewContainer!, child: imageView!, left: imageViewLeftInset, right: imageViewRightInset)
imageViewContainer!.addConstraints(Layout.constraint("V:|-(imageViewTopInset)-[imageView(maximumImageViewHeight)]-(imageViewBottomInset)-|", options: [], metrics: ["imageViewTopInset": imageViewTopInset, "imageViewBottomInset": imageViewBottomInset, "maximumImageViewHeight": maximumImageViewHeight], views: ["imageView": imageView!]))
}
// title
if nil != titleLabel {
// clear for updated constraints
titleLabelContainer!.removeConstraints(titleLabelContainer!.constraints)
if nil == imageView {
// container
layoutConstraints += Layout.constraint("H:|[titleLabelContainer]|", options: [], metrics: nil, views: ["titleLabelContainer": titleLabelContainer!])
verticalFormat += "[titleLabelContainer]"
views["titleLabelContainer"] = titleLabelContainer!
} else {
//container
Layout.alignFromBottomLeft(imageViewContainer!, child: titleLabelContainer!)
Layout.expandToParentHorizontally(imageViewContainer!, child: titleLabelContainer!)
}
// common text
if 0 == maximumTitleLabelHeight {
Layout.expandToParentWithPad(titleLabelContainer!, child: titleLabel!, top: titleLabelTopInset, left: titleLabelLeftInset, bottom: titleLabelBottomInset, right: titleLabelRightInset)
} else {
Layout.expandToParentHorizontallyWithPad(titleLabelContainer!, child: titleLabel!, left: titleLabelLeftInset, right: titleLabelRightInset)
titleLabelContainer!.addConstraints(Layout.constraint("V:|-(titleLabelTopInset)-[titleLabel(<=maximumTitleLabelHeight)]-(titleLabelBottomInset)-|", options: [], metrics: ["titleLabelTopInset": titleLabelTopInset, "titleLabelBottomInset": titleLabelBottomInset, "maximumTitleLabelHeight": maximumTitleLabelHeight], views: ["titleLabel": titleLabel!]))
}
}
// detail
if nil != detailLabel {
// clear for updated constraints
detailLabelContainer!.removeConstraints(detailLabelContainer!.constraints)
// container
layoutConstraints += Layout.constraint("H:|[detailLabelContainer]|", options: [], metrics: nil, views: ["detailLabelContainer": detailLabelContainer!])
verticalFormat += "[detailLabelContainer]"
views["detailLabelContainer"] = detailLabelContainer!
// text
if 0 == maximumDetailLabelHeight {
Layout.expandToParentWithPad(detailLabelContainer!, child: detailLabel!, top: detailLabelTopInset, left: detailLabelLeftInset, bottom: detailLabelBottomInset, right: detailLabelRightInset)
} else {
Layout.expandToParentHorizontallyWithPad(detailLabelContainer!, child: detailLabel!, left: detailLabelLeftInset, right: detailLabelRightInset)
detailLabelContainer!.addConstraints(Layout.constraint("V:|-(detailLabelTopInset)-[detailLabel(<=maximumDetailLabelHeight)]-(detailLabelBottomInset)-|", options: [], metrics: ["detailLabelTopInset": detailLabelTopInset, "detailLabelBottomInset": detailLabelBottomInset, "maximumDetailLabelHeight": maximumDetailLabelHeight], views: ["detailLabel": detailLabel!]))
}
}
// buttons
if nil != leftButtons || nil != rightButtons {
// clear for updated constraints
buttonsContainer!.removeConstraints(buttonsContainer!.constraints)
// divider
if nil != divider {
layoutConstraints += Layout.constraint("H:|[divider]|", options: [], metrics: nil, views: ["divider": divider!])
views["divider"] = divider!
verticalFormat += "[divider(1)]"
}
//container
layoutConstraints += Layout.constraint("H:|[buttonsContainer]|", options: [], metrics: nil, views: ["buttonsContainer": buttonsContainer!])
verticalFormat += "[buttonsContainer]"
views["buttonsContainer"] = buttonsContainer!
// leftButtons
if nil != leftButtons {
var horizontalFormat: String = "H:|"
var buttonViews: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
for var i: Int = 0, l: Int = leftButtons!.count; i < l; ++i {
let button: MaterialButton = leftButtons![i]
buttonsContainer!.addSubview(button)
buttonViews["button\(i)"] = button
horizontalFormat += "-(buttonLeftInset)-[button\(i)]"
Layout.expandToParentVerticallyWithPad(buttonsContainer!, child: button, top: buttonTopInset, bottom: buttonBottomInset)
}
buttonsContainer!.addConstraints(Layout.constraint(horizontalFormat, options: [], metrics: ["buttonLeftInset": buttonLeftInset], views: buttonViews))
}
// rightButtons
if nil != rightButtons {
var horizontalFormat: String = "H:"
var buttonViews: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
for var i: Int = 0, l: Int = rightButtons!.count; i < l; ++i {
let button: MaterialButton = rightButtons![i]
buttonsContainer!.addSubview(button)
buttonViews["button\(i)"] = button
horizontalFormat += "[button\(i)]-(buttonRightInset)-"
Layout.expandToParentVerticallyWithPad(buttonsContainer!, child: button, top: buttonTopInset, bottom: buttonBottomInset)
}
buttonsContainer!.addConstraints(Layout.constraint(horizontalFormat + "|", options: [], metrics: ["buttonRightInset": buttonRightInset], views: buttonViews))
}
}
verticalFormat += "|"
// combine constraints
if 0 < layoutConstraints.count {
layoutConstraints += Layout.constraint(verticalFormat, options: [], metrics: nil, views: views)
NSLayoutConstraint.activateConstraints(layoutConstraints)
}
}
//
// :name: prepareProperties
//
internal func prepareProperties(imageView: UIImageView?, titleLabel: UILabel?, detailLabel: UILabel?, divider: UIView?, leftButtons: Array<MaterialButton>?, rightButtons: Array<MaterialButton>?) {
self.imageView = imageView
self.titleLabel = titleLabel
self.detailLabel = detailLabel
self.divider = divider
self.leftButtons = leftButtons
self.rightButtons = rightButtons
}
//
// :name: prepareView
//
internal override func prepareView() {
super.prepareView()
prepareShadow()
backgroundColor = MaterialTheme.color.white.base
}
}
public func <=(lhs: ImageCardView, rhs: ImageCardView) -> Bool {
return lhs.tag <= rhs.tag
}
public func >=(lhs: ImageCardView, rhs: ImageCardView) -> Bool {
return lhs.tag >= rhs.tag
}
public func >(lhs: ImageCardView, rhs: ImageCardView) -> Bool {
return lhs.tag > rhs.tag
}
public func <(lhs: ImageCardView, rhs: ImageCardView) -> Bool {
return lhs.tag < rhs.tag
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public struct Layout {
/**
:name: width
*/
public static func width(parent: UIView, child: UIView, width: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["width" : width]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:[child(width)]", options: [], metrics: metrics, views: views))
}
/**
:name: height
*/
public static func height(parent: UIView, child: UIView, height: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["height" : height]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("V:[child(height)]", options: [], metrics: metrics, views: views))
}
/**
:name: size
*/
public static func size(parent: UIView, child: UIView, width: CGFloat = 0, height: CGFloat = 0) {
Layout.width(parent, child: child, width: width)
Layout.height(parent, child: child, height: height)
}
/**
:name: expandToParent
*/
public static func expandToParent(parent: UIView, child: UIView) {
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|[child]|", options: [], metrics: nil, views: views))
parent.addConstraints(constraint("V:|[child]|", options: [], metrics: nil, views: views))
}
/**
:name: expandToParentHorizontally
*/
public static func expandToParentHorizontally(parent: UIView, child: UIView) {
expandToParentHorizontallyWithPad(parent, child: child, left: 0, right: 0)
}
/**
:name: expandToParentHorizontallyWithPad
*/
public static func expandToParentHorizontallyWithPad(parent: UIView, child: UIView, left: CGFloat = 0, right: CGFloat = 0) {
parent.addConstraints(constraint("H:|-(left)-[child]-(right)-|", options: [], metrics: ["left": left, "right": right], views: ["child" : child]))
}
/**
:name: expandToParentVertically
*/
public static func expandToParentVertically(parent: UIView, child: UIView) {
expandToParentVerticallyWithPad(parent, child: child, top: 0, bottom: 0)
}
/**
:name: expandToParentVerticallyWithPad
*/
public static func expandToParentVerticallyWithPad(parent: UIView, child: UIView, top: CGFloat = 0, bottom: CGFloat = 0) {
parent.addConstraints(constraint("V:|-(top)-[child]-(bottom)-|", options: [], metrics: ["bottom": bottom, "top": top], views: ["child" : child]))
}
/**
:name: expandToParentWithPad
*/
public static func expandToParentWithPad(parent: UIView, child: UIView, top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) {
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|-(left)-[child]-(right)-|", options: [], metrics: ["left": left, "right": right], views: views))
parent.addConstraints(constraint("V:|-(top)-[child]-(bottom)-|", options: [], metrics: ["bottom": bottom, "top": top], views: views))
}
/**
:name: alignFromTopLeft
*/
public static func alignFromTopLeft(parent: UIView, child: UIView, top: CGFloat = 0, left: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["top" : top, "left" : left]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|-(left)-[child]", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:|-(top)-[child]", options: [], metrics: metrics, views: views))
}
/**
:name: alignFromTopRight
*/
public static func alignFromTopRight(parent: UIView, child: UIView, top: CGFloat = 0, right: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["top" : top, "right" : right]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:[child]-(right)-|", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:|-(top)-[child]", options: [], metrics: metrics, views: views))
}
/**
:name: alignFromBottomLeft
*/
public static func alignFromBottomLeft(parent: UIView, child: UIView, bottom: CGFloat = 0, left: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["bottom" : bottom, "left" : left]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|-(left)-[child]", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: [], metrics: metrics, views: views))
}
/**
:name: alignFromBottomRight
*/
public static func alignFromBottomRight(parent: UIView, child: UIView, bottom: CGFloat = 0, right: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["bottom" : bottom, "right" : right]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:[child]-(right)-|", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: [], metrics: metrics, views: views))
}
/**
:name: alignFromTop
*/
public static func alignFromTop(parent: UIView, child: UIView, top: CGFloat = 0) {
parent.addConstraints(constraint("V:|-(top)-[child]", options: [], metrics: ["top" : top], views: ["child" : child]))
}
/**
:name: alignFromLeft
*/
public static func alignFromLeft(parent: UIView, child: UIView, left: CGFloat = 0) {
parent.addConstraints(constraint("H:|-(left)-[child]", options: [], metrics: ["left" : left], views: ["child" : child]))
}
/**
:name: alignFromBottom
*/
public static func alignFromBottom(parent: UIView, child: UIView, bottom: CGFloat = 0) {
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: [], metrics: ["bottom" : bottom], views: ["child" : child]))
}
/**
:name: alignFromRight
*/
public static func alignFromRight(parent: UIView, child: UIView, right: CGFloat = 0) {
parent.addConstraints(constraint("H:[child]-(right)-|", options: [], metrics: ["right" : right], views: ["child" : child]))
}
/**
:name: alignAllSides
*/
public static func alignAllSides(parent: UIView, child: UIView) {
expandToParent(parent, child: child)
}
/**
:name: constraint
*/
public static func constraint(format: String, options: NSLayoutFormatOptions, metrics: Dictionary<String, AnyObject>?, views: Dictionary<String, AnyObject>) -> Array<NSLayoutConstraint> {
return NSLayoutConstraint.constraintsWithVisualFormat(
format,
options: options,
metrics: metrics,
views: views
)
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class MaterialButton : UIButton {
//
// :name: backgroundColorView
//
internal lazy var backgroundColorView: UIView = UIView()
//
// :name: pulseView
//
internal var pulseView: UIView?
/**
:name: backgroundColor
*/
public override var backgroundColor: UIColor? {
get {
return backgroundColorView.backgroundColor
}
set(value) {
backgroundColorView.backgroundColor = value
}
}
/**
:name: pulseColor
*/
public var pulseColor: UIColor? = MaterialTheme.color.white.base
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
/**
:name: init
*/
public required override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectZero)
}
/**
:name: touchesBegan
*/
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
pulseBegan(touches, withEvent: event)
}
/**
:name: touchesEnded
*/
public override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
shrink()
pulseEnded(touches, withEvent: event)
}
/**
:name: touchesCancelled
*/
public override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
super.touchesCancelled(touches, withEvent: event)
shrink()
pulseEnded(touches, withEvent: event)
}
/**
:name: drawRect
*/
final public override func drawRect(rect: CGRect) {
prepareBackgroundColorView()
prepareButton()
}
//
// :name: prepareView
//
internal func prepareView() {
translatesAutoresizingMaskIntoConstraints = false
}
//
// :name: prepareButton
//
internal func prepareButton() {}
//
// :name: prepareShadow
//
internal func prepareShadow() {
layer.shadowColor = MaterialTheme.color.black.base.CGColor
layer.shadowOffset = CGSizeMake(0.1, 0.1)
layer.shadowOpacity = 0.4
layer.shadowRadius = 2
}
//
// :name: pulseBegan
//
internal func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
pulseView = UIView(frame: CGRectMake(0, 0, bounds.height, bounds.height))
pulseView!.layer.cornerRadius = bounds.height / 2
pulseView!.center = (touches.first as! UITouch).locationInView(self)
pulseView!.backgroundColor = pulseColor?.colorWithAlphaComponent(0.3)
backgroundColorView.addSubview(pulseView!)
}
//
// :name: pulseEnded
//
internal func pulseEnded(touches: Set<NSObject>?, withEvent event: UIEvent?) {
UIView.animateWithDuration(0.3,
animations: { _ in
self.pulseView?.alpha = 0
}
) { _ in
self.pulseView?.removeFromSuperview()
self.pulseView = nil
}
}
//
// :name: prepareBackgroundColorView
//
private func prepareBackgroundColorView() {
backgroundColorView.translatesAutoresizingMaskIntoConstraints = false
backgroundColorView.layer.masksToBounds = true
backgroundColorView.clipsToBounds = true
backgroundColorView.userInteractionEnabled = false
insertSubview(backgroundColorView, atIndex: 0)
Layout.expandToParent(self, child: backgroundColorView)
}
//
// :name: shrink
//
private func shrink() {
UIView.animateWithDuration(0.3,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 10,
options: [],
animations: {
self.transform = CGAffineTransformIdentity
},
completion: nil
)
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class MaterialCardView : UIView {
//
// :name: backgroundColorView
//
internal lazy var backgroundColorView: UIView = UIView()
//
// :name: pulseViewContainer
//
internal lazy var pulseViewContainer: UIView = UIView()
//
// :name: pulseView
//
internal var pulseView: UIView?
/**
:name: backgroundColor
*/
public override var backgroundColor: UIColor? {
get {
return backgroundColorView.backgroundColor
}
set(value) {
backgroundColorView.backgroundColor = value
}
}
/**
:name: pulseColor
*/
public var pulseColor: UIColor? = MaterialTheme.color.blueGrey.lighten3
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
/**
:name: init
*/
public required override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectZero)
}
/**
:name: touchesBegan
*/
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
pulseBegan(touches, withEvent: event)
}
/**
:name: touchesEnded
*/
public override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
shrink()
pulseEnded(touches, withEvent: event)
}
/**
:name: touchesCancelled
*/
public override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
super.touchesCancelled(touches, withEvent: event)
shrink()
pulseEnded(touches, withEvent: event)
}
//
// :name: prepareView
//
internal func prepareView() {
translatesAutoresizingMaskIntoConstraints = false
prepareBackgroundColorView()
preparePulseViewContainer()
}
//
// :name: prepareShadow
//
internal func prepareShadow() {
layer.shadowColor = MaterialTheme.color.black.base.CGColor
layer.shadowOffset = CGSizeMake(0.1, 0.1)
layer.shadowOpacity = 0.4
layer.shadowRadius = 2
}
//
// :name: removeShadow
//
internal func removeShadow() {
layer.shadowColor = MaterialTheme.color.clear.base.CGColor
layer.shadowOffset = CGSizeMake(0, 0)
layer.shadowOpacity = 0
layer.shadowRadius = 0
}
//
// :name: layoutSubviews
//
public override func layoutSubviews() {
super.layoutSubviews()
layer.shadowPath = UIBezierPath(rect: bounds).CGPath
}
//
// :name: pulseBegan
//
internal func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
let width: CGFloat = bounds.size.width / 3
pulseView = UIView(frame: CGRectMake(0, 0, width, width))
pulseView!.layer.cornerRadius = width / 2
pulseView!.center = (touches.first as! UITouch).locationInView(self)
pulseView!.backgroundColor = pulseColor?.colorWithAlphaComponent(0.3)
addSubview(pulseViewContainer)
Layout.expandToParent(self, child: pulseViewContainer)
pulseViewContainer.addSubview(pulseView!)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(3, 3)
self.transform = CGAffineTransformMakeScale(1.05, 1.05)
}, completion: nil)
}
//
// :name: pulseEnded
//
internal func pulseEnded(touches: Set<NSObject>?, withEvent event: UIEvent?) {
UIView.animateWithDuration(0.3,
animations: { _ in
self.pulseView?.alpha = 0
}
) { _ in
self.pulseViewContainer.removeFromSuperview()
self.pulseView?.removeFromSuperview()
self.pulseView = nil
}
}
//
// :name: prepareBackgroundColorView
//
// We need this view so we can use the masksToBounds
// so the pulse doesn't animate off the button
private func prepareBackgroundColorView() {
backgroundColorView.translatesAutoresizingMaskIntoConstraints = false
backgroundColorView.layer.cornerRadius = 2
backgroundColorView.layer.masksToBounds = true
backgroundColorView.clipsToBounds = true
backgroundColorView.userInteractionEnabled = false
insertSubview(backgroundColorView, atIndex: 0)
Layout.expandToParent(self, child: backgroundColorView)
}
//
// :name: preparePulseViewContainer
//
// We need this view so we can use the masksToBounds
// so the pulse doesn't animate off the button
private func preparePulseViewContainer() {
pulseViewContainer.translatesAutoresizingMaskIntoConstraints = false
pulseViewContainer.layer.cornerRadius = 2
pulseViewContainer.layer.masksToBounds = true
pulseViewContainer.clipsToBounds = true
pulseViewContainer.userInteractionEnabled = false
}
//
// :name: shrink
//
private func shrink() {
UIView.animateWithDuration(0.3,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 10,
options: [],
animations: {
self.transform = CGAffineTransformIdentity
},
completion: nil
)
}
}
......@@ -19,21 +19,20 @@
import UIKit
// color
public extension MaterialTheme {
public struct color {
public struct MaterialColor {
// clear
public struct clear {
public static let base: UIColor = UIColor.clearColor()
public static let color: UIColor = UIColor.clearColor()
}
// white
public struct white {
public static let base: UIColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
public static let color: UIColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
}
// black
public struct black {
public static let base: UIColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1)
public static let color: UIColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 1)
}
// red
......@@ -43,7 +42,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 239/255, green: 154/255, blue: 254/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 229/255, green: 115/255, blue: 115/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 229/255, green: 83/255, blue: 80/255, alpha: 1)
public static let base: UIColor = UIColor(red: 244/255, green: 67/255, blue: 54/255, alpha: 1)
public static let color: UIColor = UIColor(red: 244/255, green: 67/255, blue: 54/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 229/255, green: 57/255, blue: 53/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 211/255, green: 47/255, blue: 47/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 198/255, green: 40/255, blue: 40/255, alpha: 1)
......@@ -61,7 +60,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 244/255, green: 143/255, blue: 177/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 240/255, green: 98/255, blue: 146/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 236/255, green: 64/255, blue: 122/255, alpha: 1)
public static let base: UIColor = UIColor(red: 233/255, green: 30/255, blue: 99/255, alpha: 1)
public static let color: UIColor = UIColor(red: 233/255, green: 30/255, blue: 99/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 216/255, green: 27/255, blue: 96/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 194/255, green: 24/255, blue: 191/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 173/255, green: 20/255, blue: 87/255, alpha: 1)
......@@ -79,7 +78,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 206/255, green: 147/255, blue: 216/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 186/255, green: 104/255, blue: 200/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 171/255, green: 71/255, blue: 188/255, alpha: 1)
public static let base: UIColor = UIColor(red: 156/255, green: 39/255, blue: 176/255, alpha: 1)
public static let color: UIColor = UIColor(red: 156/255, green: 39/255, blue: 176/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 142/255, green: 36/255, blue: 170/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 123/255, green: 31/255, blue: 162/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 106/255, green: 27/255, blue: 154/255, alpha: 1)
......@@ -97,7 +96,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 179/255, green: 157/255, blue: 219/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 149/255, green: 117/255, blue: 205/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 126/255, green: 87/255, blue: 194/255, alpha: 1)
public static let base: UIColor = UIColor(red: 103/255, green: 58/255, blue: 183/255, alpha: 1)
public static let color: UIColor = UIColor(red: 103/255, green: 58/255, blue: 183/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 94/255, green: 53/255, blue: 177/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 81/255, green: 45/255, blue: 168/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 69/255, green: 39/255, blue: 160/255, alpha: 1)
......@@ -115,7 +114,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 159/255, green: 168/255, blue: 218/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 121/255, green: 134/255, blue: 203/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 92/255, green: 107/255, blue: 192/255, alpha: 1)
public static let base: UIColor = UIColor(red: 63/255, green: 81/255, blue: 181/255, alpha: 1)
public static let color: UIColor = UIColor(red: 63/255, green: 81/255, blue: 181/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 57/255, green: 73/255, blue: 171/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 48/255, green: 63/255, blue: 159/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 40/255, green: 53/255, blue: 147/255, alpha: 1)
......@@ -133,7 +132,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 144/255, green: 202/255, blue: 249/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 100/255, green: 181/255, blue: 246/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 66/255, green: 165/255, blue: 245/255, alpha: 1)
public static let base: UIColor = UIColor(red: 33/255, green: 150/255, blue: 243/255, alpha: 1)
public static let color: UIColor = UIColor(red: 33/255, green: 150/255, blue: 243/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 30/255, green: 136/255, blue: 229/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 25/255, green: 118/255, blue: 210/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 21/255, green: 101/255, blue: 192/255, alpha: 1)
......@@ -151,7 +150,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 129/255, green: 212/255, blue: 250/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 79/255, green: 195/255, blue: 247/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 41/255, green: 182/255, blue: 246/255, alpha: 1)
public static let base: UIColor = UIColor(red: 3/255, green: 169/255, blue: 244/255, alpha: 1)
public static let color: UIColor = UIColor(red: 3/255, green: 169/255, blue: 244/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 3/255, green: 155/255, blue: 229/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 2/255, green: 136/255, blue: 209/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 2/255, green: 119/255, blue: 189/255, alpha: 1)
......@@ -169,7 +168,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 128/255, green: 222/255, blue: 2343/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 77/255, green: 208/255, blue: 225/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 38/255, green: 198/255, blue: 218/255, alpha: 1)
public static let base: UIColor = UIColor(red: 0/255, green: 188/255, blue: 212/255, alpha: 1)
public static let color: UIColor = UIColor(red: 0/255, green: 188/255, blue: 212/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 0/255, green: 172/255, blue: 193/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 0/255, green: 151/255, blue: 167/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 0/255, green: 131/255, blue: 143/255, alpha: 1)
......@@ -187,7 +186,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 128/255, green: 203/255, blue: 196/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 77/255, green: 182/255, blue: 172/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 38/255, green: 166/255, blue: 154/255, alpha: 1)
public static let base: UIColor = UIColor(red: 0/255, green: 150/255, blue: 136/255, alpha: 1)
public static let color: UIColor = UIColor(red: 0/255, green: 150/255, blue: 136/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 0/255, green: 137/255, blue: 123/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 0/255, green: 121/255, blue: 107/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 0/255, green: 105/255, blue: 92/255, alpha: 1)
......@@ -205,7 +204,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 165/255, green: 214/255, blue: 167/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 129/255, green: 199/255, blue: 132/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 102/255, green: 187/255, blue: 106/255, alpha: 1)
public static let base: UIColor = UIColor(red: 76/255, green: 175/255, blue: 80/255, alpha: 1)
public static let color: UIColor = UIColor(red: 76/255, green: 175/255, blue: 80/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 67/255, green: 160/255, blue: 71/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 56/255, green: 142/255, blue: 60/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 46/255, green: 125/255, blue: 50/255, alpha: 1)
......@@ -223,7 +222,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 197/255, green: 225/255, blue: 165/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 174/255, green: 213/255, blue: 129/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 156/255, green: 204/255, blue: 101/255, alpha: 1)
public static let base: UIColor = UIColor(red: 139/255, green: 195/255, blue: 74/255, alpha: 1)
public static let color: UIColor = UIColor(red: 139/255, green: 195/255, blue: 74/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 124/255, green: 179/255, blue: 66/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 104/255, green: 159/255, blue: 56/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 85/255, green: 139/255, blue: 47/255, alpha: 1)
......@@ -241,7 +240,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 230/255, green: 238/255, blue: 156/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 220/255, green: 231/255, blue: 117/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 212/255, green: 225/255, blue: 87/255, alpha: 1)
public static let base: UIColor = UIColor(red: 205/255, green: 220/255, blue: 57/255, alpha: 1)
public static let color: UIColor = UIColor(red: 205/255, green: 220/255, blue: 57/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 192/255, green: 202/255, blue: 51/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 175/255, green: 180/255, blue: 43/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 158/255, green: 157/255, blue: 36/255, alpha: 1)
......@@ -259,7 +258,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 255/255, green: 245/255, blue: 157/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 255/255, green: 241/255, blue: 118/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 255/255, green: 238/255, blue: 88/255, alpha: 1)
public static let base: UIColor = UIColor(red: 255/255, green: 235/255, blue: 59/255, alpha: 1)
public static let color: UIColor = UIColor(red: 255/255, green: 235/255, blue: 59/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 253/255, green: 216/255, blue: 53/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 251/255, green: 192/255, blue: 45/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 249/255, green: 168/255, blue: 37/255, alpha: 1)
......@@ -277,7 +276,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 255/255, green: 224/255, blue: 130/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 255/255, green: 213/255, blue: 79/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 255/255, green: 202/255, blue: 40/255, alpha: 1)
public static let base: UIColor = UIColor(red: 255/255, green: 193/255, blue: 7/255, alpha: 1)
public static let color: UIColor = UIColor(red: 255/255, green: 193/255, blue: 7/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 255/255, green: 179/255, blue: 0/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 255/255, green: 160/255, blue: 0/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 255/255, green: 143/255, blue: 0/255, alpha: 1)
......@@ -295,7 +294,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 255/255, green: 204/255, blue: 128/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 255/255, green: 183/255, blue: 77/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 255/255, green: 167/255, blue: 38/255, alpha: 1)
public static let base: UIColor = UIColor(red: 255/255, green: 152/255, blue: 0/255, alpha: 1)
public static let color: UIColor = UIColor(red: 255/255, green: 152/255, blue: 0/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 251/255, green: 140/255, blue: 0/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 245/255, green: 124/255, blue: 0/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 239/255, green: 108/255, blue: 0/255, alpha: 1)
......@@ -314,7 +313,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 255/255, green: 171/255, blue: 145/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 255/255, green: 138/255, blue: 101/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 255/255, green: 112/255, blue: 67/255, alpha: 1)
public static let base: UIColor = UIColor(red: 255/255, green: 87/255, blue: 34/255, alpha: 1)
public static let color: UIColor = UIColor(red: 255/255, green: 87/255, blue: 34/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 244/255, green: 81/255, blue: 30/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 230/255, green: 74/255, blue: 25/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 216/255, green: 67/255, blue: 21/255, alpha: 1)
......@@ -333,7 +332,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 188/255, green: 170/255, blue: 164/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 161/255, green: 136/255, blue: 127/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 141/255, green: 110/255, blue: 99/255, alpha: 1)
public static let base: UIColor = UIColor(red: 121/255, green: 85/255, blue: 72/255, alpha: 1)
public static let color: UIColor = UIColor(red: 121/255, green: 85/255, blue: 72/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 109/255, green: 76/255, blue: 65/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 93/255, green: 64/255, blue: 55/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 78/255, green: 52/255, blue: 46/255, alpha: 1)
......@@ -347,7 +346,7 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 238/255, green: 238/255, blue: 238/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 224/255, green: 224/255, blue: 224/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 189/255, green: 189/255, blue: 189/255, alpha: 1)
public static let base: UIColor = UIColor(red: 158/255, green: 158/255, blue: 158/255, alpha: 1)
public static let color: UIColor = UIColor(red: 158/255, green: 158/255, blue: 158/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 117/255, green: 117/255, blue: 117/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 97/255, green: 97/255, blue: 97/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 66/255, green: 66/255, blue: 66/255, alpha: 1)
......@@ -361,11 +360,10 @@ public extension MaterialTheme {
public static let lighten3: UIColor = UIColor(red: 176/255, green: 190/255, blue: 197/255, alpha: 1)
public static let lighten2: UIColor = UIColor(red: 144/255, green: 164/255, blue: 174/255, alpha: 1)
public static let lighten1: UIColor = UIColor(red: 120/255, green: 144/255, blue: 156/255, alpha: 1)
public static let base: UIColor = UIColor(red: 96/255, green: 125/255, blue: 139/255, alpha: 1)
public static let color: UIColor = UIColor(red: 96/255, green: 125/255, blue: 139/255, alpha: 1)
public static let darken1: UIColor = UIColor(red: 84/255, green: 110/255, blue: 122/255, alpha: 1)
public static let darken2: UIColor = UIColor(red: 69/255, green: 90/255, blue: 100/255, alpha: 1)
public static let darken3: UIColor = UIColor(red: 55/255, green: 71/255, blue: 79/255, alpha: 1)
public static let darken4: UIColor = UIColor(red: 38/255, green: 50/255, blue: 56/255, alpha: 1)
}
}
}
......@@ -18,12 +18,18 @@
import UIKit
public struct Roboto {
// font
public struct MaterialFont {
/**
:name: pointSize
*/
public static var pointSize: CGFloat = 16
/**
:name: thin
*/
public static var thin: UIFont {
return thinWithSize(MaterialTheme.font.pointSize)
return thinWithSize(MaterialFont.pointSize)
}
/**
......@@ -40,7 +46,7 @@ public struct Roboto {
:name: light
*/
public static var light: UIFont {
return lightWithSize(MaterialTheme.font.pointSize)
return lightWithSize(MaterialFont.pointSize)
}
/**
......@@ -57,7 +63,7 @@ public struct Roboto {
:name: regular
*/
public static var regular: UIFont {
return regularWithSize(MaterialTheme.font.pointSize)
return regularWithSize(MaterialFont.pointSize)
}
/**
......@@ -74,7 +80,7 @@ public struct Roboto {
:name: medium
*/
public static var medium: UIFont {
return mediumWithSize(MaterialTheme.font.pointSize)
return mediumWithSize(MaterialFont.pointSize)
}
/**
......@@ -91,7 +97,7 @@ public struct Roboto {
:name: bold
*/
public static var bold: UIFont {
return boldWithSize(MaterialTheme.font.pointSize)
return boldWithSize(MaterialFont.pointSize)
}
/**
......
......@@ -67,65 +67,3 @@ public func MaterialGravityToString(gravity: MaterialGravity) -> String {
return kCAGravityResizeAspectFill
}
}
\ No newline at end of file
// MaterialTheme
public extension MaterialTheme {
public struct view {}
public struct navigation {}
}
// view
public extension MaterialTheme.view {
// frame
public static var x: CGFloat = 0
public static let y: CGFloat = 0
public static let width: CGFloat = UIScreen.mainScreen().bounds.width
public static let height: CGFloat = UIScreen.mainScreen().bounds.height
// layer
public static let shadowColor: UIColor = MaterialTheme.color.blueGrey.darken4
public static let shadowOffset: CGSize = CGSizeMake(0.2, 0.2)
public static let shadowOpacity: Float = 0.5
public static let shadowRadius: CGFloat = 1
public static let masksToBounds: Bool = false
// color
public static let backgroudColor: UIColor = MaterialTheme.color.white.base
// interaction
public static let userInteractionEnabled: Bool = true
// image
public static let contentsGravity: MaterialGravity = .ResizeAspectFill
public static let contentsRect: CGRect = CGRectMake(0, 0, 1, 1)
public static let contentsScale: CGFloat = UIScreen.mainScreen().scale
}
// navigation
public extension MaterialTheme.navigation {
// frame
public static let x: CGFloat = MaterialTheme.view.x
public static let y: CGFloat = MaterialTheme.view.y
public static let width: CGFloat = MaterialTheme.view.width
public static let height: CGFloat = 70
// layer
public static let shadowColor: UIColor = MaterialTheme.view.shadowColor
public static let shadowOffset: CGSize = MaterialTheme.view.shadowOffset
public static let shadowOpacity: Float = MaterialTheme.view.shadowOpacity
public static let shadowRadius: CGFloat = MaterialTheme.view.shadowRadius
public static let masksToBounds: Bool = MaterialTheme.view.masksToBounds
// color
public static let backgroudColor: UIColor = MaterialTheme.color.blue.accent2
public static let lightContentStatusBar: Bool = true
// interaction
public static let userInteractionEnabled: Bool = false
// image
public static let contentsGravity: MaterialGravity = MaterialTheme.view.contentsGravity
public static let contentsRect: CGRect = MaterialTheme.view.contentsRect
public static let contentsScale: CGFloat = MaterialTheme.view.contentsScale
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
@objc(MaterialTextDelegate)
public protocol TextDelegate {
optional func textStorageWillProcessEdit(text: MaterialText, textStorage: MaterialTextStorage, string: String, range: NSRange)
optional func textStorageDidProcessEdit(text: MaterialText, textStorage: MaterialTextStorage, string: String, result: NSTextCheckingResult?, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>)
}
@objc(MaterialText)
public class MaterialText: NSObject {
/**
:name: searchPattern
:description: A string representation of the regular expression that matches text within
the TextStorage string property. By default, the search pattern recognizes words and emoji
haracters beginning with hashtags.
*/
public var searchPattern: String = "(^|\\s)#[\\d\\w_\u{203C}\u{2049}\u{20E3}\u{2122}\u{2139}\u{2194}-\u{2199}\u{21A9}-\u{21AA}\u{231A}-\u{231B}\u{23E9}-\u{23EC}\u{23F0}\u{23F3}\u{24C2}\u{25AA}-\u{25AB}\u{25B6}\u{25C0}\u{25FB}-\u{25FE}\u{2600}-\u{2601}\u{260E}\u{2611}\u{2614}-\u{2615}\u{261D}\u{263A}\u{2648}-\u{2653}\u{2660}\u{2663}\u{2665}-\u{2666}\u{2668}\u{267B}\u{267F}\u{2693}\u{26A0}-\u{26A1}\u{26AA}-\u{26AB}\u{26BD}-\u{26BE}\u{26C4}-\u{26C5}\u{26CE}\u{26D4}\u{26EA}\u{26F2}-\u{26F3}\u{26F5}\u{26FA}\u{26FD}\u{2702}\u{2705}\u{2708}-\u{270C}\u{270F}\u{2712}\u{2714}\u{2716}\u{2728}\u{2733}-\u{2734}\u{2744}\u{2747}\u{274C}\u{274E}\u{2753}-\u{2755}\u{2757}\u{2764}\u{2795}-\u{2797}\u{27A1}\u{27B0}\u{2934}-\u{2935}\u{2B05}-\u{2B07}\u{2B1B}-\u{2B1C}\u{2B50}\u{2B55}\u{3030}\u{303D}\u{3297}\u{3299}\u{1F004}\u{1F0CF}\u{1F170}-\u{1F171}\u{1F17E}-\u{1F17F}\u{1F18E}\u{1F191}-\u{1F19A}\u{1F1E7}-\u{1F1EC}\u{1F1EE}-\u{1F1F0}\u{1F1F3}\u{1F1F5}\u{1F1F7}-\u{1F1FA}\u{1F201}-\u{1F202}\u{1F21A}\u{1F22F}\u{1F232}-\u{1F23A}\u{1F250}-\u{1F251}\u{1F300}-\u{1F320}\u{1F330}-\u{1F335}\u{1F337}-\u{1F37C}\u{1F380}-\u{1F393}\u{1F3A0}-\u{1F3C4}\u{1F3C6}-\u{1F3CA}\u{1F3E0}-\u{1F3F0}\u{1F400}-\u{1F43E}\u{1F440}\u{1F442}-\u{1F4F7}\u{1F4F9}-\u{1F4FC}\u{1F500}-\u{1F507}\u{1F509}-\u{1F53D}\u{1F550}-\u{1F567}\u{1F5FB}-\u{1F640}\u{1F645}-\u{1F64F}\u{1F680}-\u{1F68A}]+" {
didSet {
textStorage.searchExpression = try? NSRegularExpression(pattern: searchPattern, options: [])
}
}
/**
:name: textStorage
:description: Reference to wrapped NSTextStorage
*/
public let textStorage: MaterialTextStorage
/**
:name: delegate
:description: An optional instance of TextDelegate to handle text processing events.
*/
public weak var delegate: TextDelegate?
/**
:name: init
*/
public override init() {
textStorage = MaterialTextStorage()
super.init()
textStorage.searchExpression = try? NSRegularExpression(pattern: searchPattern, options: [])
textStorage.textStorageWillProcessEdit = { (textStorage: MaterialTextStorage, string: String, range: NSRange) -> Void in
self.delegate?.textStorageWillProcessEdit?(self, textStorage: textStorage, string: string, range: range)
}
textStorage.textStorageDidProcessEdit = { (textStorage: MaterialTextStorage, result: NSTextCheckingResult?, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.delegate?.textStorageDidProcessEdit?(self, textStorage: textStorage, string: textStorage.string, result: result, flags: flags, stop: stop)
}
}
/**
:name: string
:description: Managed string value.
*/
public var string: String {
get {
return textStorage.string
}
}
/**
:name: matches
:description: An array of matches found in the TextStorage string property based on the
searchPattern property.
*/
public var matches: Array<String> {
get {
let results: Array<NSTextCheckingResult> = textStorage.searchExpression!.matchesInString(string, options: [], range: NSMakeRange(0, string.utf16.count))
return unique(results.map {(self.string as NSString).substringWithRange($0.range)})
}
}
/**
:name: unique
:description: Ensures a unique value in the matches return array.
*/
private func unique<S: SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] {
var seen: [E:Bool] = [:]
return source.filter {nil == seen.updateValue(true, forKey: $0)}
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
internal typealias MaterialTextStorageWillProcessEdit = (MaterialTextStorage, String, NSRange) -> Void
internal typealias MaterialTextStorageDidProcessEdit = (MaterialTextStorage, NSTextCheckingResult?, NSMatchingFlags, UnsafeMutablePointer<ObjCBool>) -> Void
public class MaterialTextStorage: NSTextStorage {
/**
:name: store
:description: Acts as the model, storing the string value.
*/
private lazy var store: NSMutableAttributedString = NSMutableAttributedString()
/**
:name: searchExpression
:description: Matches text within the TextStorage string property.
*/
internal var searchExpression: NSRegularExpression?
/**
:name: textStorageWillProcessEdit
:description: If set, this block callback executes when there is a change in the TextStorage
string value.
*/
internal var textStorageWillProcessEdit: MaterialTextStorageWillProcessEdit?
/**
:name: textStorageDidProcessEdit
:description: If set, this block callback executes when a match is detected after a change in
the TextStorage string value.
*/
internal var textStorageDidProcessEdit: MaterialTextStorageDidProcessEdit?
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public override init() {
super.init()
}
/**
:name: string
:description: Managed string value.
*/
override public var string: String {
get {
return store.string
}
}
/**
:name: processEditing
*/
public override func processEditing() {
let range: NSRange = (string as NSString).paragraphRangeForRange(editedRange)
textStorageWillProcessEdit?(self, string, range)
searchExpression!.enumerateMatchesInString(string, options: [], range: range) { (result: NSTextCheckingResult?, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.textStorageDidProcessEdit?(self, result, flags, stop)
}
super.processEditing()
}
/**
:name: attributesAtIndex
*/
public override func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> [String : AnyObject] {
return store.attributesAtIndex(location, effectiveRange: range)
}
/**
:name: replaceCharactersInRange
*/
public override func replaceCharactersInRange(range: NSRange, withString str: String) {
store.replaceCharactersInRange(range, withString: str)
edited(NSTextStorageEditActions.EditedCharacters, range: range, changeInLength: str.utf16.count - range.length)
}
/**
:name: setAttributes
*/
public override func setAttributes(attrs: [String : AnyObject]?, range: NSRange) {
store.setAttributes(attrs, range: range)
edited(NSTextStorageEditActions.EditedAttributes, range: range, changeInLength: 0)
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
// font
public extension MaterialTheme {
public struct font {
public static var pointSize: CGFloat = 16
}
}
\ No newline at end of file
......@@ -18,16 +18,65 @@
import UIKit
public struct MaterialTheme {}
public struct MaterialTheme {
public struct view {}
public struct navigation {}
}
// view
public extension MaterialTheme.view {
// frame
public static var x: CGFloat = 0
public static let y: CGFloat = 0
public static let width: CGFloat = UIScreen.mainScreen().bounds.width
public static let height: CGFloat = UIScreen.mainScreen().bounds.height
// layer
public static let shadowColor: UIColor = MaterialColor.blueGrey.darken4
public static let shadowOffset: CGSize = CGSizeMake(0.2, 0.2)
public static let shadowOpacity: Float = 0.5
public static let shadowRadius: CGFloat = 1
public static let masksToBounds: Bool = false
// color
public static let backgroudColor: UIColor = MaterialColor.white.color
// interaction
public static let userInteractionEnabled: Bool = true
// spacing
public extension MaterialTheme {
public static var cardVerticalInset: CGFloat = 16
public static var cardHorizontalInset: CGFloat = 16
// image
public static let contentsRect: CGRect = CGRectMake(0, 0, 1, 1)
public static let contentsCenter: CGRect = CGRectMake(0, 0, 1, 1)
public static let contentsScale: CGFloat = UIScreen.mainScreen().scale
public static let contentsGravity: MaterialGravity = .ResizeAspectFill
}
// navigation
public extension MaterialTheme.navigation {
// frame
public static let x: CGFloat = MaterialTheme.view.x
public static let y: CGFloat = MaterialTheme.view.y
public static let width: CGFloat = MaterialTheme.view.width
public static let height: CGFloat = 70
// layer
public static let shadowColor: UIColor = MaterialTheme.view.shadowColor
public static let shadowOffset: CGSize = MaterialTheme.view.shadowOffset
public static let shadowOpacity: Float = MaterialTheme.view.shadowOpacity
public static let shadowRadius: CGFloat = MaterialTheme.view.shadowRadius
public static let masksToBounds: Bool = MaterialTheme.view.masksToBounds
public static var buttonVerticalInset: CGFloat = 6
public static var buttonHorizontalInset: CGFloat = 16
// color
public static let backgroudColor: UIColor = MaterialColor.blue.accent2
public static let lightContentStatusBar: Bool = true
public static var navigationVerticalInset: CGFloat = 8
public static var navigationHorizontalInset: CGFloat = 8
// interaction
public static let userInteractionEnabled: Bool = false
// image
public static let contentsRect: CGRect = MaterialTheme.view.contentsRect
public static let contentsCenter: CGRect = MaterialTheme.view.contentsCenter
public static let contentsScale: CGFloat = MaterialTheme.view.contentsScale
public static let contentsGravity: MaterialGravity = MaterialTheme.view.contentsGravity
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class RaisedButton : MaterialButton {
//
// :name: prepareButton
//
internal override func prepareView() {
super.prepareView()
titleLabel!.font = Roboto.regular
setTitleColor(MaterialTheme.color.white.base, forState: .Normal)
backgroundColor = MaterialTheme.color.blue.accent2
contentEdgeInsets = UIEdgeInsetsMake(MaterialTheme.buttonVerticalInset, MaterialTheme.buttonHorizontalInset, MaterialTheme.buttonVerticalInset, MaterialTheme.buttonHorizontalInset)
}
//
// :name: prepareButton
//
internal override func prepareButton() {
super.prepareButton()
prepareShadow()
backgroundColorView.layer.cornerRadius = 3
}
//
// :name: pulseBegan
//
internal override func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent?) {
super.pulseBegan(touches, withEvent: event)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(4, 4)
self.transform = CGAffineTransformMakeScale(1.05, 1.05)
})
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
extension UIViewController {
/**
:name: sideNavigationViewController
*/
public var sideNavigationViewController: SideNavigationViewController? {
var viewController: UIViewController? = self
while nil != viewController {
if viewController is SideNavigationViewController {
return viewController as? SideNavigationViewController
}
viewController = viewController?.parentViewController
}
return nil
}
}
public enum SideNavigationViewState {
case Opened
case Closed
}
@objc(SideNavigationViewContainer)
public class SideNavigationViewContainer : NSObject {
/**
:name: state
*/
public private(set) var state: SideNavigationViewState
/**
:name: point
*/
public private(set) var point: CGPoint
/**
:name: frame
*/
public private(set) var frame: CGRect
/**
:name: description
*/
public override var description: String {
let s: String = .Opened == state ? "Opened" : "Closed"
return "(state: \(s), point: \(point), frame: \(frame))"
}
/**
:name: init
*/
public init(state: SideNavigationViewState, point: CGPoint, frame: CGRect) {
self.state = state
self.point = point
self.frame = frame
}
}
@objc(SideNavigationViewDelegate)
public protocol SideNavigationViewDelegate {
// left
optional func sideNavDidBeginLeftPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidChangeLeftPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidEndLeftPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidOpenLeftViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidCloseLeftViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidTapLeft(nav: SideNavigationViewController, container: SideNavigationViewContainer)
// right
optional func sideNavDidBeginRightPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidChangeRightPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidEndRightPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidOpenRightViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidCloseRightViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidTapRight(nav: SideNavigationViewController, container: SideNavigationViewContainer)
// bottom
optional func sideNavDidBeginBottomPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidChangeBottomPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidEndBottomPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidOpenBottomViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidCloseBottomViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidTapBottom(nav: SideNavigationViewController, container: SideNavigationViewContainer)
// top
optional func sideNavDidBeginTopPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidChangeTopPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidEndTopPan(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidOpenTopViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidCloseTopViewContainer(nav: SideNavigationViewController, container: SideNavigationViewContainer)
optional func sideNavDidTapTop(nav: SideNavigationViewController, container: SideNavigationViewContainer)
}
@objc(SideNavigationViewController)
public class SideNavigationViewController: UIViewController, UIGestureRecognizerDelegate {
/**
:name: default options
*/
public struct defaultOptions {
public static var bezelWidth: CGFloat = 48
public static var bezelHeight: CGFloat = 48
public static var containerWidth: CGFloat = 240
public static var containerHeight: CGFloat = 240
public static var defaultAnimationDuration: CGFloat = 0.3
public static var threshold: CGFloat = 48
public static var panningEnabled: Bool = true
}
/**
:name: options
*/
public struct options {
public static var shadowOpacity: Float = 0
public static var shadowRadius: CGFloat = 0
public static var shadowOffset: CGSize = CGSizeZero
public static var backdropScale: CGFloat = 1
public static var backdropOpacity: CGFloat = 0.5
public static var hideStatusBar: Bool = true
public static var horizontalThreshold: CGFloat = defaultOptions.threshold
public static var verticalThreshold: CGFloat = defaultOptions.threshold
public static var backdropBackgroundColor: UIColor = MaterialTheme.color.black.base
public static var animationDuration: CGFloat = defaultOptions.defaultAnimationDuration
public static var leftBezelWidth: CGFloat = defaultOptions.bezelWidth
public static var leftViewContainerWidth: CGFloat = defaultOptions.containerWidth
public static var leftPanFromBezel: Bool = defaultOptions.panningEnabled
public static var rightBezelWidth: CGFloat = defaultOptions.bezelWidth
public static var rightViewContainerWidth: CGFloat = defaultOptions.containerWidth
public static var rightPanFromBezel: Bool = defaultOptions.panningEnabled
public static var bottomBezelHeight: CGFloat = defaultOptions.bezelHeight
public static var bottomViewContainerHeight: CGFloat = defaultOptions.containerHeight
public static var bottomPanFromBezel: Bool = defaultOptions.panningEnabled
public static var topBezelHeight: CGFloat = defaultOptions.bezelHeight
public static var topViewContainerHeight: CGFloat = defaultOptions.containerHeight
public static var topPanFromBezel: Bool = defaultOptions.panningEnabled
}
/**
:name: delegate
*/
public weak var delegate: SideNavigationViewDelegate?
/**
:name: isViewBasedAppearance
*/
public var isViewBasedAppearance: Bool {
return 0 == NSBundle.mainBundle().objectForInfoDictionaryKey("UIViewControllerBasedStatusBarAppearance") as? Int
}
/**
:name: isLeftContainerOpened
*/
public var isLeftContainerOpened: Bool {
if let c = leftViewContainer {
return c.frame.origin.x != leftOriginX
}
return false
}
/**
:name: isRightContainerOpened
*/
public var isRightContainerOpened: Bool {
if let c = rightViewContainer {
return c.frame.origin.x != rightOriginX
}
return false
}
/**
:name: isBottomContainerOpened
*/
public var isBottomContainerOpened: Bool {
if let c = bottomViewContainer {
return c.frame.origin.y != bottomOriginY
}
return false
}
/**
:name: isTopContainerOpened
*/
public var isTopContainerOpened: Bool {
if let c = topViewContainer {
return c.frame.origin.y != topOriginY
}
return false
}
/**
:name: isUserInteractionEnabled
*/
public var isUserInteractionEnabled: Bool {
get {
return mainViewContainer!.userInteractionEnabled
}
set(value) {
mainViewContainer?.userInteractionEnabled = value
}
}
/**
:name: backdropViewContainer
*/
public private(set) var backdropViewContainer: UIView?
/**
:name: mainViewContainer
*/
public private(set) var mainViewContainer: UIView?
/**
:name: leftViewContainer
*/
public private(set) var leftViewContainer: UIView?
/**
:name: rightViewContainer
*/
public private(set) var rightViewContainer: UIView?
/**
:name: bottomViewContainer
*/
public private(set) var bottomViewContainer: UIView?
/**
:name: bottomViewContainer
*/
public private(set) var topViewContainer: UIView?
/**
:name: leftContainer
*/
public private(set) var leftContainer: SideNavigationViewContainer?
/**
:name: rightContainer
*/
public private(set) var rightContainer: SideNavigationViewContainer?
/**
:name: bottomContainer
*/
public private(set) var bottomContainer: SideNavigationViewContainer?
/**
:name: topContainer
*/
public private(set) var topContainer: SideNavigationViewContainer?
/**
:name: mainViewController
*/
public var mainViewController: UIViewController?
/**
:name: leftViewController
*/
public var leftViewController: UIViewController?
/**
:name: rightViewController
*/
public var rightViewController: UIViewController?
/**
:name: leftViewController
*/
public var bottomViewController: UIViewController?
/**
:name: topViewController
*/
public var topViewController: UIViewController?
/**
:name: leftPanGesture
*/
public var leftPanGesture: UIPanGestureRecognizer?
/**
:name: leftTapGesture
*/
public var leftTapGesture: UITapGestureRecognizer?
/**
:name: rightTapGesture
*/
public var rightTapGesture: UITapGestureRecognizer?
/**
:name: rightTapGesture
*/
public var bottomTapGesture: UITapGestureRecognizer?
/**
:name: topTapGesture
*/
public var topTapGesture: UITapGestureRecognizer?
/**
:name: rightPanGesture
*/
public var rightPanGesture: UIPanGestureRecognizer?
/**
:name: rightPanGesture
*/
public var bottomPanGesture: UIPanGestureRecognizer?
/**
:name: rightPanGesture
*/
public var topPanGesture: UIPanGestureRecognizer?
//
// :name: leftOriginX
//
private var leftOriginX: CGFloat {
return -options.leftViewContainerWidth
}
//
// :name: rightOriginX
//
private var rightOriginX: CGFloat {
return view.bounds.width
}
//
// :name: bottomOriginY
//
private var bottomOriginY: CGFloat {
return view.bounds.height
}
//
// :name: topOriginY
//
private var topOriginY: CGFloat {
return -options.topViewContainerHeight
}
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, leftViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.leftViewController = leftViewController
prepareView()
prepareLeftView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, rightViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.rightViewController = rightViewController
prepareView()
prepareRightView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, bottomViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.bottomViewController = bottomViewController
prepareView()
prepareBottomView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, topViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.topViewController = topViewController
prepareView()
prepareTopView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, leftViewController: UIViewController, rightViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.leftViewController = leftViewController
self.rightViewController = rightViewController
prepareView()
prepareLeftView()
prepareRightView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, leftViewController: UIViewController, bottomViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.leftViewController = leftViewController
self.bottomViewController = bottomViewController
prepareView()
prepareLeftView()
prepareBottomView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, leftViewController: UIViewController, bottomViewController: UIViewController, rightViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.leftViewController = leftViewController
self.bottomViewController = bottomViewController
self.rightViewController = rightViewController
prepareView()
prepareLeftView()
prepareBottomView()
prepareRightView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, leftViewController: UIViewController, bottomViewController: UIViewController, rightViewController: UIViewController, topViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.leftViewController = leftViewController
self.bottomViewController = bottomViewController
self.rightViewController = rightViewController
self.topViewController = topViewController
prepareView()
prepareLeftView()
prepareBottomView()
prepareRightView()
prepareTopView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, bottomViewController: UIViewController, rightViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.bottomViewController = bottomViewController
self.rightViewController = rightViewController
prepareView()
prepareBottomView()
prepareRightView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, bottomViewController: UIViewController, topViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.bottomViewController = bottomViewController
self.topViewController = topViewController
prepareView()
prepareBottomView()
prepareTopView()
}
/**
:name: init
*/
public convenience init(mainViewController: UIViewController, rightViewController: UIViewController, topViewController: UIViewController) {
self.init()
self.mainViewController = mainViewController
self.rightViewController = rightViewController
self.topViewController = topViewController
prepareView()
prepareRightView()
prepareTopView()
}
//
// :name: viewDidLoad
//
public override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = .None
}
//
// :name: viewWillLayoutSubviews
//
public override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if mainViewController != nil {
prepareContainedViewController(&mainViewContainer, viewController: &mainViewController)
}
if leftViewController != nil {
prepareContainedViewController(&leftViewContainer, viewController: &leftViewController)
}
if rightViewController != nil {
prepareContainedViewController(&rightViewContainer, viewController: &rightViewController)
}
if bottomViewController != nil {
prepareContainedViewController(&bottomViewContainer, viewController: &bottomViewController)
}
if topViewController != nil {
prepareContainedViewController(&topViewContainer, viewController: &topViewController)
}
}
/**
:name: toggleLeftViewContainer
*/
public func toggleLeftViewContainer(velocity: CGFloat = 0) {
isLeftContainerOpened ? closeLeftViewContainer(velocity) : openLeftViewContainer(velocity)
}
/**
:name: toggleRightViewContainer
*/
public func toggleRightViewContainer(velocity: CGFloat = 0) {
isRightContainerOpened ? closeRightViewContainer(velocity) : openRightViewContainer(velocity)
}
/**
:name: toggleBottomViewContainer
*/
public func toggleBottomViewContainer(velocity: CGFloat = 0) {
isBottomContainerOpened ? closeBottomViewContainer(velocity) : openBottomViewContainer(velocity)
}
/**
:name: toggleTopViewContainer
*/
public func toggleTopViewContainer(velocity: CGFloat = 0) {
isTopContainerOpened ? closeTopViewContainer(velocity) : openTopViewContainer(velocity)
}
/**
:name: openLeftViewContainer
*/
public func openLeftViewContainer(velocity: CGFloat = 0) {
if let vc = leftViewContainer {
if let c = leftContainer {
prepareContainerToOpen(&leftViewController, viewContainer: &leftViewContainer, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, Double(vc.frame.origin.x / velocity)))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.x = 0
self.backdropViewContainer?.layer.opacity = Float(options.backdropOpacity)
self.mainViewContainer?.transform = CGAffineTransformMakeScale(options.backdropScale, options.backdropScale)
}
) { _ in
self.isUserInteractionEnabled = false
}
c.state = .Opened
delegate?.sideNavDidOpenLeftViewContainer?(self, container: c)
}
}
}
/**
:name: openRightViewContainer
*/
public func openRightViewContainer(velocity: CGFloat = 0) {
if let vc = rightViewContainer {
if let c = rightContainer {
prepareContainerToOpen(&rightViewController, viewContainer: &rightViewContainer, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, Double(fabs(vc.frame.origin.x - rightOriginX) / velocity)))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.x = self.rightOriginX - vc.frame.size.width
self.backdropViewContainer?.layer.opacity = Float(options.backdropOpacity)
self.mainViewContainer?.transform = CGAffineTransformMakeScale(options.backdropScale, options.backdropScale)
}
) { _ in
self.isUserInteractionEnabled = false
}
c.state = .Opened
delegate?.sideNavDidOpenRightViewContainer?(self, container: c)
}
}
}
/**
:name: openBottomViewContainer
*/
public func openBottomViewContainer(velocity: CGFloat = 0) {
if let vc = bottomViewContainer {
if let c = bottomContainer {
prepareContainerToOpen(&bottomViewController, viewContainer: &bottomViewContainer, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, Double(fabs(vc.frame.origin.y - bottomOriginY) / velocity)))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.y = self.bottomOriginY - vc.frame.size.height
self.backdropViewContainer?.layer.opacity = Float(options.backdropOpacity)
self.mainViewContainer?.transform = CGAffineTransformMakeScale(options.backdropScale, options.backdropScale)
}
) { _ in
self.isUserInteractionEnabled = false
}
c.state = .Opened
delegate?.sideNavDidOpenRightViewContainer?(self, container: c)
}
}
}
/**
:name: openTopViewContainer
*/
public func openTopViewContainer(velocity: CGFloat = 0) {
if let vc = topViewContainer {
if let c = topContainer {
prepareContainerToOpen(&topViewController, viewContainer: &topViewContainer, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, Double(fabs(vc.frame.origin.y + topOriginY) / velocity)))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.y = self.topOriginY + vc.frame.size.height
self.backdropViewContainer?.layer.opacity = Float(options.backdropOpacity)
self.mainViewContainer?.transform = CGAffineTransformMakeScale(options.backdropScale, options.backdropScale)
}
) { _ in
self.isUserInteractionEnabled = false
}
c.state = .Opened
delegate?.sideNavDidOpenTopViewContainer?(self, container: c)
}
}
}
/**
:name: closeLeftViewContainer
*/
public func closeLeftViewContainer(velocity: CGFloat = 0) {
if let vc = leftViewContainer {
if let c = leftContainer {
prepareContainerToClose(&leftViewController, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, fabs(vc.frame.origin.x - leftOriginX) / velocity))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.x = self.leftOriginX
self.backdropViewContainer?.layer.opacity = 0
self.mainViewContainer?.transform = CGAffineTransformMakeScale(1, 1)
}
) { _ in
self.removeShadow(&self.leftViewContainer)
self.isUserInteractionEnabled = true
}
c.state = .Closed
delegate?.sideNavDidCloseLeftViewContainer?(self, container: c)
}
}
}
/**
:name: closeRightViewContainer
*/
public func closeRightViewContainer(velocity: CGFloat = 0) {
if let vc = rightViewContainer {
if let c = rightContainer {
prepareContainerToClose(&rightViewController, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, fabs(vc.frame.origin.x - rightOriginX) / velocity))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.x = self.rightOriginX
self.backdropViewContainer?.layer.opacity = 0
self.mainViewContainer?.transform = CGAffineTransformMakeScale(1, 1)
}
) { _ in
self.removeShadow(&self.rightViewContainer)
self.isUserInteractionEnabled = true
}
c.state = .Closed
delegate?.sideNavDidCloseRightViewContainer?(self, container: c)
}
}
}
/**
:name: closeBottomViewContainer
*/
public func closeBottomViewContainer(velocity: CGFloat = 0) {
if let vc = bottomViewContainer {
if let c = bottomContainer {
prepareContainerToClose(&bottomViewController, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, fabs(vc.frame.origin.y - bottomOriginY) / velocity))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.y = self.bottomOriginY
self.backdropViewContainer?.layer.opacity = 0
self.mainViewContainer?.transform = CGAffineTransformMakeScale(1, 1)
}
) { _ in
self.removeShadow(&self.bottomViewContainer)
self.isUserInteractionEnabled = true
}
c.state = .Closed
delegate?.sideNavDidCloseBottomViewContainer?(self, container: c)
}
}
}
/**
:name: closeBottomViewContainer
*/
public func closeTopViewContainer(velocity: CGFloat = 0) {
if let vc = topViewContainer {
if let c = topContainer {
prepareContainerToClose(&topViewController, state: c.state)
UIView.animateWithDuration(Double(0 == velocity ? options.animationDuration : fmax(0.1, fmin(1, fabs(vc.frame.origin.y - topOriginY) / velocity))),
delay: 0,
options: .CurveEaseInOut,
animations: { _ in
vc.frame.origin.y = self.topOriginY
self.backdropViewContainer?.layer.opacity = 0
self.mainViewContainer?.transform = CGAffineTransformMakeScale(1, 1)
}
) { _ in
self.removeShadow(&self.topViewContainer)
self.isUserInteractionEnabled = true
}
c.state = .Closed
delegate?.sideNavDidCloseBottomViewContainer?(self, container: c)
}
}
}
/**
:name: switchMainViewController
*/
public func switchMainViewController(viewController: UIViewController, closeViewContainers: Bool) {
removeViewController(&mainViewController)
mainViewController = viewController
prepareContainedViewController(&mainViewContainer, viewController: &mainViewController)
if closeViewContainers {
closeLeftViewContainer()
closeRightViewContainer()
}
}
/**
:name: switchLeftViewController
*/
public func switchLeftViewController(viewController: UIViewController, closeLeftViewContainerViewContainer: Bool) {
removeViewController(&leftViewController)
leftViewController = viewController
prepareContainedViewController(&leftViewContainer, viewController: &leftViewController)
if closeLeftViewContainerViewContainer {
closeLeftViewContainer()
}
}
/**
:name: switchRightViewController
*/
public func switchRightViewController(viewController: UIViewController, closeRightViewContainerViewContainer: Bool) {
removeViewController(&rightViewController)
rightViewController = viewController
prepareContainedViewController(&rightViewContainer, viewController: &rightViewController)
if closeRightViewContainerViewContainer {
closeRightViewContainer()
}
}
/**
:name: switchBottomViewController
*/
public func switchBottomViewController(viewController: UIViewController, closeBottomViewContainerViewContainer: Bool) {
removeViewController(&rightViewController)
rightViewController = viewController
prepareContainedViewController(&rightViewContainer, viewController: &rightViewController)
if closeBottomViewContainerViewContainer {
closeBottomViewContainer()
}
}
/**
:name: switchTopViewController
*/
public func switchTopViewController(viewController: UIViewController, closeTopViewContainerViewContainer: Bool) {
removeViewController(&topViewController)
topViewController = viewController
prepareContainedViewController(&topViewContainer, viewController: &topViewController)
if closeTopViewContainerViewContainer {
closeTopViewContainer()
}
}
//
// :name: gestureRecognizer
//
public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if gestureRecognizer == leftPanGesture {
return gesturePanLeftViewController(gestureRecognizer, withTouchPoint: touch.locationInView(view))
}
if gestureRecognizer == rightPanGesture {
return gesturePanRightViewController(gestureRecognizer, withTouchPoint: touch.locationInView(view))
}
if gestureRecognizer == bottomPanGesture {
return gesturePanBottomViewController(gestureRecognizer, withTouchPoint: touch.locationInView(view))
}
if gestureRecognizer == topPanGesture {
return gesturePanTopViewController(gestureRecognizer, withTouchPoint: touch.locationInView(view))
}
if gestureRecognizer == leftTapGesture {
return isLeftContainerOpened && !isPointContainedWithinViewController(&leftViewContainer, point: touch.locationInView(view))
}
if gestureRecognizer == rightTapGesture {
return isRightContainerOpened && !isPointContainedWithinViewController(&rightViewContainer, point: touch.locationInView(view))
}
if gestureRecognizer == bottomTapGesture {
return isBottomContainerOpened && !isPointContainedWithinViewController(&bottomViewContainer, point: touch.locationInView(view))
}
if gestureRecognizer == topTapGesture {
return isTopContainerOpened && !isPointContainedWithinViewController(&topViewContainer, point: touch.locationInView(view))
}
return true
}
//
// :name: prepareView
//
internal func prepareView() {
prepareMainContainer()
prepareBackdropContainer()
}
//
// :name: prepareLeftView
//
internal func prepareLeftView() {
prepareContainer(&leftContainer, viewContainer: &leftViewContainer, originX: leftOriginX, originY: 0, width: options.leftViewContainerWidth, height: view.bounds.size.height)
prepareLeftGestures()
}
//
// :name: prepareRightView
//
internal func prepareRightView() {
prepareContainer(&rightContainer, viewContainer: &rightViewContainer, originX: rightOriginX, originY: 0, width: options.rightViewContainerWidth, height: view.bounds.size.height)
prepareRightGestures()
}
//
// :name: prepareBottomView
//
internal func prepareBottomView() {
prepareContainer(&bottomContainer, viewContainer: &bottomViewContainer, originX: 0, originY: bottomOriginY, width: view.bounds.size.width, height: options.bottomViewContainerHeight)
prepareBottomGestures()
}
//
// :name: prepareBottomView
//
internal func prepareTopView() {
prepareContainer(&topContainer, viewContainer: &topViewContainer, originX: 0, originY: topOriginY, width: view.bounds.size.width, height: options.topViewContainerHeight)
prepareTopGestures()
}
//
// :name: addGestures
//
private func addGestures(inout pan: UIPanGestureRecognizer?, panSelector: Selector, inout tap: UITapGestureRecognizer?, tapSelector: Selector) {
if nil == pan {
pan = UIPanGestureRecognizer(target: self, action: panSelector)
pan!.delegate = self
view.addGestureRecognizer(pan!)
}
if nil == tap {
tap = UITapGestureRecognizer(target: self, action: tapSelector)
tap!.delegate = self
view.addGestureRecognizer(tap!)
}
}
//
// :name: removeGestures
//
private func removeGestures(inout pan: UIPanGestureRecognizer?, inout tap: UITapGestureRecognizer?) {
if let g = pan {
view.removeGestureRecognizer(g)
pan = nil
}
if let g = tap {
view.removeGestureRecognizer(g)
tap = nil
}
}
//
// :name: handleLeftPanGesture
//
internal func handleLeftPanGesture(gesture: UIPanGestureRecognizer) {
if isRightContainerOpened || isBottomContainerOpened || isTopContainerOpened { return }
if let vc = leftViewContainer {
if let c = leftContainer {
if .Began == gesture.state {
addShadow(&leftViewContainer)
toggleStatusBar(true)
c.state = isLeftContainerOpened ? .Opened : .Closed
c.point = gesture.locationInView(view)
c.frame = vc.frame
delegate?.sideNavDidBeginLeftPan?(self, container: c)
} else if .Changed == gesture.state {
c.point = gesture.translationInView(gesture.view!)
let r = (vc.frame.origin.x - leftOriginX) / vc.frame.size.width
let s: CGFloat = 1 - (1 - options.backdropScale) * r
let x: CGFloat = c.frame.origin.x + c.point.x
vc.frame.origin.x = x < leftOriginX ? leftOriginX : x > 0 ? 0 : x
backdropViewContainer?.layer.opacity = Float(r * options.backdropOpacity)
mainViewContainer?.transform = CGAffineTransformMakeScale(s, s)
delegate?.sideNavDidChangeLeftPan?(self, container: c)
} else {
c.point = gesture.velocityInView(gesture.view)
let x: CGFloat = c.point.x >= 1000 || c.point.x <= -1000 ? c.point.x : 0
c.state = vc.frame.origin.x <= CGFloat(floor(leftOriginX)) + options.horizontalThreshold || c.point.x <= -1000 ? .Closed : .Opened
if .Closed == c.state {
closeLeftViewContainer(x)
} else {
openLeftViewContainer(x)
}
delegate?.sideNavDidEndLeftPan?(self, container: c)
}
}
}
}
//
// :name: handleLeftTapGesture
//
internal func handleLeftTapGesture(gesture: UIPanGestureRecognizer) {
if let c = leftContainer {
delegate?.sideNavDidTapLeft?(self, container: c)
closeLeftViewContainer()
}
}
//
// :name: handleRightPanGesture
//
internal func handleRightPanGesture(gesture: UIPanGestureRecognizer) {
if isLeftContainerOpened || isBottomContainerOpened || isTopContainerOpened { return }
if let vc = rightViewContainer {
if let c = rightContainer {
if .Began == gesture.state {
c.point = gesture.locationInView(view)
c.state = isRightContainerOpened ? .Opened : .Closed
c.frame = vc.frame
addShadow(&rightViewContainer)
toggleStatusBar(true)
delegate?.sideNavDidBeginRightPan?(self, container: c)
} else if .Changed == gesture.state {
c.point = gesture.translationInView(gesture.view!)
let r = (rightOriginX - vc.frame.origin.x) / vc.frame.size.width
let m: CGFloat = rightOriginX - vc.frame.size.width
let x: CGFloat = c.frame.origin.x + c.point.x
vc.frame.origin.x = x > rightOriginX ? rightOriginX : x < m ? m : x
backdropViewContainer?.layer.opacity = Float(r * options.backdropOpacity)
delegate?.sideNavDidChangeRightPan?(self, container: c)
} else {
c.point = gesture.velocityInView(gesture.view)
let x: CGFloat = c.point.x <= -1000 || c.point.x >= 1000 ? c.point.x : 0
c.state = vc.frame.origin.x >= CGFloat(floor(rightOriginX) - options.horizontalThreshold) || c.point.x >= 1000 ? .Closed : .Opened
if .Closed == c.state {
closeRightViewContainer(x)
} else {
openRightViewContainer(x)
}
delegate?.sideNavDidEndRightPan?(self, container: c)
}
}
}
}
//
// :name: handleRightTapGesture
//
internal func handleRightTapGesture(gesture: UIPanGestureRecognizer) {
if let c = rightContainer {
delegate?.sideNavDidTapRight?(self, container: c)
closeRightViewContainer()
}
}
//
// :name: handleBottomPanGesture
//
internal func handleBottomPanGesture(gesture: UIPanGestureRecognizer) {
if isLeftContainerOpened || isRightContainerOpened || isTopContainerOpened { return }
if let vc = bottomViewContainer {
if let c = bottomContainer {
if .Began == gesture.state {
addShadow(&bottomViewContainer)
toggleStatusBar(true)
c.state = isBottomContainerOpened ? .Opened : .Closed
c.point = gesture.locationInView(view)
c.frame = vc.frame
delegate?.sideNavDidBeginBottomPan?(self, container: c)
} else if .Changed == gesture.state {
c.point = gesture.translationInView(gesture.view!)
let r = (bottomOriginY - vc.frame.origin.y) / vc.frame.size.height
let m: CGFloat = bottomOriginY - vc.frame.size.height
let y: CGFloat = c.frame.origin.y + c.point.y
vc.frame.origin.y = y > bottomOriginY ? bottomOriginY : y < m ? m : y
backdropViewContainer?.layer.opacity = Float(r * options.backdropOpacity)
delegate?.sideNavDidChangeBottomPan?(self, container: c)
} else {
c.point = gesture.velocityInView(gesture.view)
let y: CGFloat = c.point.y <= -1000 || c.point.y >= 1000 ? c.point.y : 0
c.state = vc.frame.origin.y >= CGFloat(floor(bottomOriginY) - options.verticalThreshold) || c.point.y >= 1000 ? .Closed : .Opened
if .Closed == c.state {
closeBottomViewContainer(y)
} else {
openBottomViewContainer(y)
}
delegate?.sideNavDidEndBottomPan?(self, container: c)
}
}
}
}
//
// :name: handleRightTapGesture
//
internal func handleBottomTapGesture(gesture: UIPanGestureRecognizer) {
if let c = bottomContainer {
delegate?.sideNavDidTapBottom?(self, container: c)
closeBottomViewContainer()
}
}
//
// :name: handleTopPanGesture
//
internal func handleTopPanGesture(gesture: UIPanGestureRecognizer) {
if isLeftContainerOpened || isRightContainerOpened || isBottomContainerOpened { return }
if let vc = topViewContainer {
if let c = topContainer {
if .Began == gesture.state {
addShadow(&topViewContainer)
toggleStatusBar(true)
c.state = isTopContainerOpened ? .Opened : .Closed
c.point = gesture.locationInView(view)
c.frame = vc.frame
delegate?.sideNavDidBeginTopPan?(self, container: c)
} else if .Changed == gesture.state {
c.point = gesture.translationInView(gesture.view!)
let r = (topOriginY - vc.frame.origin.y) / vc.frame.size.height
let m: CGFloat = topOriginY + vc.frame.size.height
let y: CGFloat = c.frame.origin.y + c.point.y // increase origin y
vc.frame.origin.y = y < topOriginY ? topOriginY : y < m ? y : m
backdropViewContainer?.layer.opacity = Float(abs(r) * options.backdropOpacity)
delegate?.sideNavDidChangeTopPan?(self, container: c)
} else {
c.point = gesture.velocityInView(gesture.view)
let y: CGFloat = c.point.y <= -1000 || c.point.y >= 1000 ? c.point.y : 0
c.state = vc.frame.origin.y >= CGFloat(floor(topOriginY) + options.verticalThreshold) || c.point.y >= 1000 ? .Opened : .Closed
if .Closed == c.state {
closeTopViewContainer(y)
} else {
openTopViewContainer(y)
}
delegate?.sideNavDidEndTopPan?(self, container: c)
}
}
}
}
//
// :name: handleRightTapGesture
//
internal func handleTopTapGesture(gesture: UIPanGestureRecognizer) {
if let c = topContainer {
delegate?.sideNavDidTapTop?(self, container: c)
closeTopViewContainer()
}
}
//
// :name: addShadow
//
private func addShadow(inout viewContainer: UIView?) {
if let vc = viewContainer {
vc.layer.shadowOffset = options.shadowOffset
vc.layer.shadowOpacity = options.shadowOpacity
vc.layer.shadowRadius = options.shadowRadius
vc.layer.shadowPath = UIBezierPath(rect: vc.bounds).CGPath
vc.layer.masksToBounds = false
}
}
//
// :name: removeShadow
//
private func removeShadow(inout viewContainer: UIView?) {
if let vc = viewContainer {
vc.layer.opacity = 1
vc.layer.masksToBounds = true
}
}
//
// :name: toggleStatusBar
//
private func toggleStatusBar(hide: Bool = false) {
if options.hideStatusBar {
if isViewBasedAppearance {
UIApplication.sharedApplication().setStatusBarHidden(hide, withAnimation: .Slide)
} else {
dispatch_async(dispatch_get_main_queue(), {
if let w = UIApplication.sharedApplication().keyWindow {
w.windowLevel = hide ? UIWindowLevelStatusBar + 1 : 0
}
})
}
}
}
//
// :name: removeViewController
//
private func removeViewController(inout viewController: UIViewController?) {
if let vc = viewController {
vc.willMoveToParentViewController(nil)
vc.view.removeFromSuperview()
vc.removeFromParentViewController()
}
}
//
// :name: gesturePanLeftViewController
//
private func gesturePanLeftViewController(gesture: UIGestureRecognizer, withTouchPoint point: CGPoint) -> Bool {
return isLeftContainerOpened || options.leftPanFromBezel && isLeftPointContainedWithinRect(point)
}
//
// :name: gesturePanRightViewController
//
private func gesturePanRightViewController(gesture: UIGestureRecognizer, withTouchPoint point: CGPoint) -> Bool {
return isRightContainerOpened || options.rightPanFromBezel && isRightPointContainedWithinRect(point)
}
//
// :name: gesturePanRightViewController
//
private func gesturePanBottomViewController(gesture: UIGestureRecognizer, withTouchPoint point: CGPoint) -> Bool {
return isBottomContainerOpened || options.bottomPanFromBezel && isBottomPointContainedWithinRect(point)
}
//
// :name: gesturePanTopViewController
//
private func gesturePanTopViewController(gesture: UIGestureRecognizer, withTouchPoint point: CGPoint) -> Bool {
return isTopContainerOpened || options.topPanFromBezel && isTopPointContainedWithinRect(point)
}
//
// :name: isLeftPointContainedWithinRect
//
private func isLeftPointContainedWithinRect(point: CGPoint) -> Bool {
return CGRectContainsPoint(CGRectMake(0, 0, options.leftBezelWidth, view.bounds.size.height), point)
}
//
// :name: isRightPointContainedWithinRect
//
private func isRightPointContainedWithinRect(point: CGPoint) -> Bool {
return CGRectContainsPoint(CGRectMake(CGRectGetMaxX(view.bounds) - options.rightBezelWidth, 0, options.rightBezelWidth, view.bounds.size.height), point)
}
//
// :name: isBottomPointContainedWithinRect
//
private func isBottomPointContainedWithinRect(point: CGPoint) -> Bool {
return CGRectContainsPoint(CGRectMake(0, CGRectGetMaxY(view.bounds) - options.bottomBezelHeight, view.bounds.size.width, options.bottomBezelHeight), point)
}
//
// :name: isTopPointContainedWithinRect
//
private func isTopPointContainedWithinRect(point: CGPoint) -> Bool {
return CGRectContainsPoint(CGRectMake(0, 0, view.bounds.size.width, options.topBezelHeight), point)
}
//
// :name: isPointContainedWithinViewController
//
private func isPointContainedWithinViewController(inout viewContainer: UIView?, point: CGPoint) -> Bool {
if let vc = viewContainer {
return CGRectContainsPoint(vc.frame, point)
}
return false
}
//
// :name: prepareMainContainer
//
private func prepareMainContainer() {
mainViewContainer = UIView(frame: view.bounds)
mainViewContainer!.backgroundColor = MaterialTheme.color.clear.base
mainViewContainer!.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
view.addSubview(mainViewContainer!)
}
//
// :name: prepareBackdropContainer
//
private func prepareBackdropContainer() {
backdropViewContainer = UIView(frame: view.bounds)
backdropViewContainer!.backgroundColor = options.backdropBackgroundColor
backdropViewContainer!.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
backdropViewContainer!.layer.opacity = 0
view.addSubview(backdropViewContainer!)
}
//
// :name: prepareLeftGestures
//
private func prepareLeftGestures() {
removeGestures(&leftPanGesture, tap: &leftTapGesture)
addGestures(&leftPanGesture, panSelector: "handleLeftPanGesture:", tap: &leftTapGesture, tapSelector: "handleLeftTapGesture:")
}
//
// :name: prepareRightGestures
//
private func prepareRightGestures() {
removeGestures(&rightPanGesture, tap: &rightTapGesture)
addGestures(&rightPanGesture, panSelector: "handleRightPanGesture:", tap: &rightTapGesture, tapSelector: "handleRightTapGesture:")
}
//
// :name: prepareBottomGestures
//
private func prepareBottomGestures() {
removeGestures(&bottomPanGesture, tap: &bottomTapGesture)
addGestures(&bottomPanGesture, panSelector: "handleBottomPanGesture:", tap: &bottomTapGesture, tapSelector: "handleBottomTapGesture:")
}
//
// :name: prepareBottomGestures
//
private func prepareTopGestures() {
removeGestures(&topPanGesture, tap: &topTapGesture)
addGestures(&topPanGesture, panSelector: "handleTopPanGesture:", tap: &topTapGesture, tapSelector: "handleTopTapGesture:")
}
//
// :name: prepareContainer
//
private func prepareContainer(inout container: SideNavigationViewContainer?, inout viewContainer: UIView?, originX: CGFloat, originY: CGFloat, width: CGFloat, height: CGFloat) {
container = SideNavigationViewContainer(state: .Closed, point: CGPointZero, frame: CGRectZero)
var b: CGRect = view.bounds
b.size.width = width
b.size.height = height
b.origin.x = originX
b.origin.y = originY
viewContainer = UIView(frame: b)
viewContainer!.backgroundColor = MaterialTheme.color.clear.base
viewContainer!.autoresizingMask = .FlexibleHeight
view.addSubview(viewContainer!)
}
//
// :name: prepareContainerToOpen
//
private func prepareContainerToOpen(inout viewController: UIViewController?, inout viewContainer: UIView?, state: SideNavigationViewState) {
addShadow(&viewContainer)
toggleStatusBar(true)
}
//
// :name: prepareContainerToClose
//
private func prepareContainerToClose(inout viewController: UIViewController?, state: SideNavigationViewState) {
toggleStatusBar()
}
//
// :name: prepareContainedViewController
//
private func prepareContainedViewController(inout viewContainer: UIView?, inout viewController: UIViewController?) {
if let vc = viewController {
if let c = viewContainer {
vc.view.translatesAutoresizingMaskIntoConstraints = false
addChildViewController(vc)
c.addSubview(vc.view)
Layout.expandToParent(c, child: vc.view)
vc.didMoveToParentViewController(self)
}
}
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class TextView: UITextView {
//
// :name: layoutConstraints
//
internal lazy var layoutConstraints: Array<NSLayoutConstraint> = Array<NSLayoutConstraint>()
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
/**
:name: init
*/
public override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
if CGRectZero == frame {
translatesAutoresizingMaskIntoConstraints = false
}
prepareView()
}
//
// :name: deinit
// :description: Notification observer removed from UITextView.
//
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextViewTextDidChangeNotification, object: nil)
}
/**
:name: placeholder
:description: The placeholder label string.
*/
public var placeholderLabel: UILabel? {
didSet {
if let p = placeholderLabel {
p.translatesAutoresizingMaskIntoConstraints = false
p.font = font
p.textAlignment = textAlignment
p.numberOfLines = 0
p.backgroundColor = MaterialTheme.color.clear.base
addSubview(p)
updateLabelConstraints()
textViewTextDidChange()
}
}
}
/**
:name: text
:description: When set, updates the placeholder text.
*/
public override var text: String! {
didSet {
textViewTextDidChange()
}
}
/**
:name: attributedText
:description: When set, updates the placeholder attributedText.
*/
public override var attributedText: NSAttributedString! {
didSet {
textViewTextDidChange()
}
}
/**
:name: textContainerInset
:description: When set, updates the placeholder constraints.
*/
public override var textContainerInset: UIEdgeInsets {
didSet {
updateLabelConstraints()
}
}
public override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel?.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2
}
//
// :name: textViewTextDidChange
// :description: Updates the label visibility when text is empty or not.
//
internal func textViewTextDidChange() {
if let p = placeholderLabel {
p.hidden = !text.isEmpty
}
}
//
// :name: prepareView
// :description: Sets up the common initilized values.
//
private func prepareView() {
// label needs to be added to the view
// hierarchy before setting insets
textContainerInset = UIEdgeInsetsMake(16, 16, 16, 16)
backgroundColor = MaterialTheme.color.clear.base
NSNotificationCenter.defaultCenter().addObserver(self, selector: "textViewTextDidChange", name: UITextViewTextDidChangeNotification, object: nil)
updateLabelConstraints()
}
//
// :name: updateLabelConstraints
// :description: Updates the placeholder constraints.
//
private func updateLabelConstraints() {
if let p = placeholderLabel {
NSLayoutConstraint.deactivateConstraints(layoutConstraints)
layoutConstraints = Layout.constraint("H:|-(left)-[placeholderLabel]-(right)-|",
options: [],
metrics: [
"left": textContainerInset.left + textContainer.lineFragmentPadding,
"right": textContainerInset.right + textContainer.lineFragmentPadding
], views: [
"placeholderLabel": p
])
layoutConstraints += Layout.constraint("V:|-(top)-[placeholderLabel]-(>=bottom)-|",
options: [],
metrics: [
"top": textContainerInset.top,
"bottom": textContainerInset.bottom
],
views: [
"placeholderLabel": p
])
NSLayoutConstraint.activateConstraints(layoutConstraints)
}
}
}
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