diff --git a/CHANGELOG.md b/CHANGELOG.md index 7914ed55cdd..fec197d0c59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,96 @@ +# 10.1.0 + +## API diffs + +Auto-generated by running: + + scripts/api_diff -o dc74cd290f327e950eab32b48f3105c55972fad9 -n d4a3ac376f5c8498cfb52401f4fbb69d2e318897 + +### ActivityIndicator + +**New component.** + +### FontDiskLoader + +- [new] [`-[MDCFontDiskLoader unregisterFont]`](https://github.com/google/material-components-ios/blob/d4a3ac376f5c8498cfb52401f4fbb69d2e318897/components/FontDiskLoader/src/MDCFontDiskLoader.h#L84) +- [property attribute change] [`MDCFontDiskLoader.hasFailedRegistration`](https://github.com/google/material-components-ios/blob/d4a3ac376f5c8498cfb52401f4fbb69d2e318897/components/FontDiskLoader/src/MDCFontDiskLoader.h#L100). +Deprecated setter. +- [property attribute change] [`MDCFontDiskLoader.isRegistered`](https://github.com/google/material-components-ios/blob/d4a3ac376f5c8498cfb52401f4fbb69d2e318897/components/FontDiskLoader/src/MDCFontDiskLoader.h#L93). +Deprecated setter. +- [protocols changed] [`MDCFontDiskLoader`](https://github.com/google/material-components-ios/blob/d4a3ac376f5c8498cfb52401f4fbb69d2e318897/components/FontDiskLoader/src/MDCFontDiskLoader.h#L28). + +Added *NSCopying*. + +## Component changes + +### ActivityIndicator + +#### Changes + +* [Adding activity indicator component and demo](https://github.com/google/material-components-ios/commit/d589b27330d717c9d7a4bd1ebea562453f5c5639) (Junius Gunaratne) +* [Move layout code into supplemental, support landscape mode](https://github.com/google/material-components-ios/commit/06acbe8cb8b9aa0befea566233f5e7b7528dd8dd) (Junius Gunaratne) + +### AppBar + +#### Changes + +* [Fix typo in back item accessibility identifier.](https://github.com/google/material-components-ios/commit/f5a6ce7244edd1ad67fc8a04a0a087623936db32) (Louis Romero) +* [Respect the navigation bar's layout direction](https://github.com/google/material-components-ios/commit/c60de65ffdef1cf83d664e429615b87238f15ccf) (Louis Romero) +* [Set an accessibility identifier on the default back button.](https://github.com/google/material-components-ios/commit/ae21fd0453b3f932e2926a14518009429190c39c) (Louis Romero) + +### ButtonBar + +#### Changes + +* [Updated examples and readme to use new swift selector syntax.](https://github.com/google/material-components-ios/commit/25ea19e76a7b4d7baf9420639972127022c27602) (Eric Li) + +### Buttons + +#### Changes + +* [Updated examples and readme to use new swift selector syntax.](https://github.com/google/material-components-ios/commit/25ea19e76a7b4d7baf9420639972127022c27602) (Eric Li) + +### Collections + +#### Changes + +* [Fixes bug when initializing collection view with own layout.](https://github.com/google/material-components-ios/commit/306da8d238cfd9d85f65ccb33370e1c6485418a1) (Chris Cox) + +### FontDiskLoader + +#### Changes + +* [Added unregisterFont method.](https://github.com/google/material-components-ios/commit/77d8ebcd78cf37b9e38b77c5b29136ee37d6f719) (randallli) +* [Correct Roboto Font markdown for design specification link.](https://github.com/google/material-components-ios/commit/fa55cdd03099dfb2822e76222e81f631f7e000d0) (Yiran Mao) +* [[FontDiskLoader]? added warning NSLog when failing to load the font by name.](https://github.com/google/material-components-ios/commit/d62b6dc116d8db90e1f1953c48c0e8b6c45949de) (randallli) +* [[MDCFontDiskLoader] Added copying protocol](https://github.com/google/material-components-ios/commit/7a0a9f0aaa61d47a780fd404916701f373f7e53d) (randallli) +* [[MDCFontDiskLoader] sharing registered state across all instances of objects.](https://github.com/google/material-components-ios/commit/1ef21ea7e080664050271576fd85dcea3c4d87b4) (randallli) +* [[MDCFontDiskLoader]? Deprecated properties that should not have been public write.](https://github.com/google/material-components-ios/commit/25f4d7caec33172ef9aafc1c633c03740da62d16) (randallli) + +### PageControl + +#### Changes + +* [updated examples and readme to use new swift selector syntax](https://github.com/google/material-components-ios/commit/25ea19e76a7b4d7baf9420639972127022c27602) (Eric Li) + +### RobotoFontLoader + +#### Changes + +* [Correct Roboto Font markdown for design specification link.](https://github.com/google/material-components-ios/commit/fa55cdd03099dfb2822e76222e81f631f7e000d0) (Yiran Mao) + +### ShadowLayer + +#### Changes + +* [updated examples and readme to use new swift selector syntax](https://github.com/google/material-components-ios/commit/25ea19e76a7b4d7baf9420639972127022c27602) (Eric Li) + +### Switch + +#### Changes + +* [updated examples and readme to use new swift selector syntax](https://github.com/google/material-components-ios/commit/25ea19e76a7b4d7baf9420639972127022c27602) (Eric Li) + # 10.0.0 ## Infrastructure diff --git a/MaterialComponents.podspec b/MaterialComponents.podspec index 3125d937559..7ef4e77ee4d 100644 --- a/MaterialComponents.podspec +++ b/MaterialComponents.podspec @@ -2,7 +2,7 @@ load 'scripts/generated/icons.rb' Pod::Spec.new do |s| s.name = "MaterialComponents" - s.version = "10.0.0" + s.version = "10.1.0" s.authors = { 'Apple platform engineering at Google' => 'appleplatforms@google.com' } s.summary = "A collection of stand-alone production-ready UI libraries focused on design details." s.homepage = "https://github.com/google/material-components-ios" @@ -38,6 +38,12 @@ Pod::Spec.new do |s| # end # + s.subspec "ActivityIndicator" do |ss| + ss.public_header_files = "components/#{ss.base_name}/src/*.h" + ss.source_files = "components/#{ss.base_name}/src/*.{h,m}", "components/#{ss.base_name}/src/private/*.{h,m}" + ss.header_mappings_dir = "components/#{ss.base_name}/src/*" + end + s.subspec "AppBar" do |ss| ss.public_header_files = "components/#{ss.base_name}/src/*.h" ss.source_files = "components/#{ss.base_name}/src/*.{h,m}" @@ -80,6 +86,8 @@ Pod::Spec.new do |s| ss.source_files = "components/#{ss.base_name}/src/*.{h,m}", "components/#{ss.base_name}/src/private/*.{h,m}" ss.header_mappings_dir = "components/#{ss.base_name}/src" + ss.framework = "CoreGraphics", "QuartzCore" + ss.dependency "MaterialComponents/CollectionLayoutAttributes" ss.dependency "MaterialComponents/Ink" ss.dependency "MaterialComponents/Typography" @@ -105,6 +113,8 @@ Pod::Spec.new do |s| "Material#{ss.base_name}" => ["components/#{ss.base_name}/src/Material#{ss.base_name}.bundle/*"] } + ss.framework = "CoreGraphics", "QuartzCore" + ss.dependency "MaterialComponents/CollectionCells" ss.dependency "MaterialComponents/CollectionLayoutAttributes" ss.dependency "MaterialComponents/Ink" @@ -221,7 +231,7 @@ Pod::Spec.new do |s| end s.subspec "private" do |pss| - + # Pull in icon dependencies # The implementation of this method is generated by running scripts/sync_icons.sh # and defined in scripts/generated/icons.rb diff --git a/MaterialComponentsCatalog.podspec b/MaterialComponentsCatalog.podspec index 9cc1281ec3b..53b4d8507be 100644 --- a/MaterialComponentsCatalog.podspec +++ b/MaterialComponentsCatalog.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MaterialComponentsCatalog" - s.version = "10.0.0" + s.version = "10.1.0" s.authors = { 'Apple platform engineering at Google' => 'appleplatforms@google.com' } s.summary = "A collection of stand-alone production-ready UI libraries focused on design details." s.homepage = "https://github.com/google/material-components-ios" diff --git a/MaterialComponentsUnitTests.podspec b/MaterialComponentsUnitTests.podspec index 8e47f4bb319..25d8ab99438 100644 --- a/MaterialComponentsUnitTests.podspec +++ b/MaterialComponentsUnitTests.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MaterialComponentsUnitTests" - s.version = "10.0.0" + s.version = "10.1.0" s.authors = { 'Apple platform engineering at Google' => 'appleplatforms@google.com' } s.summary = "A collection of stand-alone production-ready UI libraries focused on design details." s.homepage = "https://github.com/google/material-components-ios" diff --git a/README.md b/README.md index 81390ca13c0..6d9d274ab80 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ class MDCBuildTestViewController: UIViewController { let raiseButton = MDCRaisedButton.init(); raiseButton.setTitle("Raised Button", forState: .Normal); raiseButton.sizeToFit(); - raiseButton.addTarget(self, action: "tapped:", forControlEvents: .TouchUpInside); + raiseButton.addTarget(self, action: #selector(tapped), forControlEvents: .TouchUpInside); self.view.addSubview(raiseButton); } diff --git a/catalog/CatalogByConvention/src/CBCNodeViewController.h b/catalog/CatalogByConvention/src/CBCNodeListViewController.h similarity index 100% rename from catalog/CatalogByConvention/src/CBCNodeViewController.h rename to catalog/CatalogByConvention/src/CBCNodeListViewController.h diff --git a/catalog/CatalogByConvention/src/CBCNodeViewController.m b/catalog/CatalogByConvention/src/CBCNodeListViewController.m similarity index 99% rename from catalog/CatalogByConvention/src/CBCNodeViewController.m rename to catalog/CatalogByConvention/src/CBCNodeListViewController.m index 810113ce437..4fe158b9f72 100644 --- a/catalog/CatalogByConvention/src/CBCNodeViewController.m +++ b/catalog/CatalogByConvention/src/CBCNodeListViewController.m @@ -14,7 +14,7 @@ limitations under the License. */ -#import "CBCNodeViewController.h" +#import "CBCNodeListViewController.h" #import "CBCCatalogExample.h" #import "CBCRuntime.h" diff --git a/catalog/CatalogByConvention/src/CatalogByConvention.h b/catalog/CatalogByConvention/src/CatalogByConvention.h index 81c321c855a..f1975f2432d 100644 --- a/catalog/CatalogByConvention/src/CatalogByConvention.h +++ b/catalog/CatalogByConvention/src/CatalogByConvention.h @@ -14,4 +14,4 @@ limitations under the License. */ -#import "CBCNodeViewController.h" +#import "CBCNodeListViewController.h" diff --git a/catalog/MDCCatalog.xcodeproj/project.pbxproj b/catalog/MDCCatalog.xcodeproj/project.pbxproj index 922bf2b43a2..e62a91c564a 100644 --- a/catalog/MDCCatalog.xcodeproj/project.pbxproj +++ b/catalog/MDCCatalog.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 664524BE1C6BA62A001ADBF8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 664524BD1C6BA62A001ADBF8 /* Assets.xcassets */; }; 664524C11C6BA62A001ADBF8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 664524BF1C6BA62A001ADBF8 /* LaunchScreen.storyboard */; }; 66519B071CCA980600E5423E /* MDCInkTouchController+Injection.m in Sources */ = {isa = PBXBuildFile; fileRef = 66519B061CCA980600E5423E /* MDCInkTouchController+Injection.m */; }; - 666CA70D1CAEBCA9001B1884 /* CBCNodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 666CA70A1CAEBCA9001B1884 /* CBCNodeViewController.m */; }; + 666CA70D1CAEBCA9001B1884 /* CBCNodeListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 666CA70A1CAEBCA9001B1884 /* CBCNodeListViewController.m */; }; 6681FDFD1CC586660013A0C7 /* MDCCatalogTileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6681FDFC1CC586660013A0C7 /* MDCCatalogTileView.swift */; }; 75F4516F2130AB879A7EDBD5 /* Pods_MDCCatalog.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A55EA1CC69E40D5EF866144 /* Pods_MDCCatalog.framework */; }; DE1944861CBD9E40009E0321 /* MDCCatalogTileData.m in Sources */ = {isa = PBXBuildFile; fileRef = DE1944681CBD9E40009E0321 /* MDCCatalogTileData.m */; }; @@ -88,8 +88,8 @@ 66519B061CCA980600E5423E /* MDCInkTouchController+Injection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MDCInkTouchController+Injection.m"; sourceTree = ""; }; 665A34D91C6BD01900962055 /* MDCCatalog-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MDCCatalog-Bridging-Header.h"; sourceTree = ""; }; 666CA7081CAEBCA9001B1884 /* CBCCatalogExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBCCatalogExample.h; sourceTree = ""; }; - 666CA7091CAEBCA9001B1884 /* CBCNodeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBCNodeViewController.h; sourceTree = ""; }; - 666CA70A1CAEBCA9001B1884 /* CBCNodeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBCNodeViewController.m; sourceTree = ""; }; + 666CA7091CAEBCA9001B1884 /* CBCNodeListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBCNodeListViewController.h; sourceTree = ""; }; + 666CA70A1CAEBCA9001B1884 /* CBCNodeListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBCNodeListViewController.m; sourceTree = ""; }; 6681FDFC1CC586660013A0C7 /* MDCCatalogTileView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MDCCatalogTileView.swift; sourceTree = ""; }; 90B4FE989AA27838D0FB6A13 /* Pods-MDCCatalog.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MDCCatalog.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MDCCatalog/Pods-MDCCatalog.debug.xcconfig"; sourceTree = ""; }; C250A4553B960CD6E1604CB7 /* Pods-MDCCatalog.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MDCCatalog.release.xcconfig"; path = "Pods/Target Support Files/Pods-MDCCatalog/Pods-MDCCatalog.release.xcconfig"; sourceTree = ""; }; @@ -212,8 +212,8 @@ children = ( 3640411C1CBECABD00C962B2 /* CatalogByConvention.h */, 666CA7081CAEBCA9001B1884 /* CBCCatalogExample.h */, - 666CA7091CAEBCA9001B1884 /* CBCNodeViewController.h */, - 666CA70A1CAEBCA9001B1884 /* CBCNodeViewController.m */, + 666CA7091CAEBCA9001B1884 /* CBCNodeListViewController.h */, + 666CA70A1CAEBCA9001B1884 /* CBCNodeListViewController.m */, 6642AB7E1CBDBE0900F5B1D7 /* private */, ); name = CatalogByConvention; @@ -434,7 +434,7 @@ files = ( DE1944901CBD9E40009E0321 /* MDCCatalogTileDataShadowLayer.m in Sources */, 6642AB811CBDBE0900F5B1D7 /* CBCRuntime.m in Sources */, - 666CA70D1CAEBCA9001B1884 /* CBCNodeViewController.m in Sources */, + 666CA70D1CAEBCA9001B1884 /* CBCNodeListViewController.m in Sources */, DE1944911CBD9E40009E0321 /* MDCCatalogTileDataSlider.m in Sources */, DE19448E1CBD9E40009E0321 /* MDCCatalogTileDataNavigationBar.m in Sources */, DE19448F1CBD9E40009E0321 /* MDCCatalogTileDataPageControl.m in Sources */, diff --git a/catalog/Podfile.lock b/catalog/Podfile.lock index 7d714a304bf..88e7c852dbf 100644 --- a/catalog/Podfile.lock +++ b/catalog/Podfile.lock @@ -1,27 +1,29 @@ PODS: - - MaterialComponents (10.0.0): - - MaterialComponents/AppBar (= 10.0.0) - - MaterialComponents/ButtonBar (= 10.0.0) - - MaterialComponents/Buttons (= 10.0.0) - - MaterialComponents/CollectionCells (= 10.0.0) - - MaterialComponents/CollectionLayoutAttributes (= 10.0.0) - - MaterialComponents/Collections (= 10.0.0) - - MaterialComponents/FlexibleHeader (= 10.0.0) - - MaterialComponents/FontDiskLoader (= 10.0.0) - - MaterialComponents/HeaderStackView (= 10.0.0) - - MaterialComponents/Ink (= 10.0.0) - - MaterialComponents/NavigationBar (= 10.0.0) - - MaterialComponents/PageControl (= 10.0.0) - - MaterialComponents/Palettes (= 10.0.0) - - MaterialComponents/private (= 10.0.0) - - MaterialComponents/RobotoFontLoader (= 10.0.0) - - MaterialComponents/ShadowElevations (= 10.0.0) - - MaterialComponents/ShadowLayer (= 10.0.0) - - MaterialComponents/Slider (= 10.0.0) - - MaterialComponents/SpritedAnimationView (= 10.0.0) - - MaterialComponents/Switch (= 10.0.0) - - MaterialComponents/Typography (= 10.0.0) - - MaterialComponents/AppBar (10.0.0): + - MaterialComponents (10.1.0): + - MaterialComponents/ActivityIndicator (= 10.1.0) + - MaterialComponents/AppBar (= 10.1.0) + - MaterialComponents/ButtonBar (= 10.1.0) + - MaterialComponents/Buttons (= 10.1.0) + - MaterialComponents/CollectionCells (= 10.1.0) + - MaterialComponents/CollectionLayoutAttributes (= 10.1.0) + - MaterialComponents/Collections (= 10.1.0) + - MaterialComponents/FlexibleHeader (= 10.1.0) + - MaterialComponents/FontDiskLoader (= 10.1.0) + - MaterialComponents/HeaderStackView (= 10.1.0) + - MaterialComponents/Ink (= 10.1.0) + - MaterialComponents/NavigationBar (= 10.1.0) + - MaterialComponents/PageControl (= 10.1.0) + - MaterialComponents/Palettes (= 10.1.0) + - MaterialComponents/private (= 10.1.0) + - MaterialComponents/RobotoFontLoader (= 10.1.0) + - MaterialComponents/ShadowElevations (= 10.1.0) + - MaterialComponents/ShadowLayer (= 10.1.0) + - MaterialComponents/Slider (= 10.1.0) + - MaterialComponents/SpritedAnimationView (= 10.1.0) + - MaterialComponents/Switch (= 10.1.0) + - MaterialComponents/Typography (= 10.1.0) + - MaterialComponents/ActivityIndicator (10.1.0) + - MaterialComponents/AppBar (10.1.0): - MaterialComponents/FlexibleHeader - MaterialComponents/HeaderStackView - MaterialComponents/NavigationBar @@ -29,14 +31,14 @@ PODS: - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/ButtonBar (10.0.0): + - MaterialComponents/ButtonBar (10.1.0): - MaterialComponents/Buttons - - MaterialComponents/Buttons (10.0.0): + - MaterialComponents/Buttons (10.1.0): - MaterialComponents/Ink - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/CollectionCells (10.0.0): + - MaterialComponents/CollectionCells (10.1.0): - MaterialComponents/CollectionLayoutAttributes - MaterialComponents/Ink - MaterialComponents/private/Icons/ic_check @@ -46,71 +48,71 @@ PODS: - MaterialComponents/private/Icons/ic_radio_button_unchecked - MaterialComponents/private/Icons/ic_reorder - MaterialComponents/Typography - - MaterialComponents/CollectionLayoutAttributes (10.0.0) - - MaterialComponents/Collections (10.0.0): + - MaterialComponents/CollectionLayoutAttributes (10.1.0) + - MaterialComponents/Collections (10.1.0): - MaterialComponents/CollectionCells - MaterialComponents/CollectionLayoutAttributes - MaterialComponents/Ink - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/FlexibleHeader (10.0.0) - - MaterialComponents/FontDiskLoader (10.0.0) - - MaterialComponents/HeaderStackView (10.0.0) - - MaterialComponents/Ink (10.0.0) - - MaterialComponents/NavigationBar (10.0.0): + - MaterialComponents/FlexibleHeader (10.1.0) + - MaterialComponents/FontDiskLoader (10.1.0) + - MaterialComponents/HeaderStackView (10.1.0) + - MaterialComponents/Ink (10.1.0) + - MaterialComponents/NavigationBar (10.1.0): - MaterialComponents/ButtonBar - MaterialComponents/Typography - - MaterialComponents/PageControl (10.0.0) - - MaterialComponents/Palettes (10.0.0) - - MaterialComponents/private (10.0.0): - - MaterialComponents/private/Color (= 10.0.0) - - MaterialComponents/private/Icons (= 10.0.0) - - MaterialComponents/private/ThumbTrack (= 10.0.0) - - MaterialComponents/private/Color (10.0.0) - - MaterialComponents/private/Icons (10.0.0): - - MaterialComponents/private/Icons/Base (= 10.0.0) - - MaterialComponents/private/Icons/ic_arrow_back (= 10.0.0) - - MaterialComponents/private/Icons/ic_check (= 10.0.0) - - MaterialComponents/private/Icons/ic_check_circle (= 10.0.0) - - MaterialComponents/private/Icons/ic_chevron_right (= 10.0.0) - - MaterialComponents/private/Icons/ic_info (= 10.0.0) - - MaterialComponents/private/Icons/ic_radio_button_unchecked (= 10.0.0) - - MaterialComponents/private/Icons/ic_reorder (= 10.0.0) - - MaterialComponents/private/Icons/Base (10.0.0) - - MaterialComponents/private/Icons/ic_arrow_back (10.0.0): + - MaterialComponents/PageControl (10.1.0) + - MaterialComponents/Palettes (10.1.0) + - MaterialComponents/private (10.1.0): + - MaterialComponents/private/Color (= 10.1.0) + - MaterialComponents/private/Icons (= 10.1.0) + - MaterialComponents/private/ThumbTrack (= 10.1.0) + - MaterialComponents/private/Color (10.1.0) + - MaterialComponents/private/Icons (10.1.0): + - MaterialComponents/private/Icons/Base (= 10.1.0) + - MaterialComponents/private/Icons/ic_arrow_back (= 10.1.0) + - MaterialComponents/private/Icons/ic_check (= 10.1.0) + - MaterialComponents/private/Icons/ic_check_circle (= 10.1.0) + - MaterialComponents/private/Icons/ic_chevron_right (= 10.1.0) + - MaterialComponents/private/Icons/ic_info (= 10.1.0) + - MaterialComponents/private/Icons/ic_radio_button_unchecked (= 10.1.0) + - MaterialComponents/private/Icons/ic_reorder (= 10.1.0) + - MaterialComponents/private/Icons/Base (10.1.0) + - MaterialComponents/private/Icons/ic_arrow_back (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_check (10.0.0): + - MaterialComponents/private/Icons/ic_check (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_check_circle (10.0.0): + - MaterialComponents/private/Icons/ic_check_circle (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_chevron_right (10.0.0): + - MaterialComponents/private/Icons/ic_chevron_right (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_info (10.0.0): + - MaterialComponents/private/Icons/ic_info (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_radio_button_unchecked (10.0.0): + - MaterialComponents/private/Icons/ic_radio_button_unchecked (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_reorder (10.0.0): + - MaterialComponents/private/Icons/ic_reorder (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/ThumbTrack (10.0.0): + - MaterialComponents/private/ThumbTrack (10.1.0): - MaterialComponents/Ink - MaterialComponents/private/Color - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - - MaterialComponents/RobotoFontLoader (10.0.0): + - MaterialComponents/RobotoFontLoader (10.1.0): - MaterialComponents/FontDiskLoader - MaterialComponents/Typography - - MaterialComponents/ShadowElevations (10.0.0) - - MaterialComponents/ShadowLayer (10.0.0) - - MaterialComponents/Slider (10.0.0): + - MaterialComponents/ShadowElevations (10.1.0) + - MaterialComponents/ShadowLayer (10.1.0) + - MaterialComponents/Slider (10.1.0): - MaterialComponents/private/ThumbTrack - - MaterialComponents/SpritedAnimationView (10.0.0) - - MaterialComponents/Switch (10.0.0): + - MaterialComponents/SpritedAnimationView (10.1.0) + - MaterialComponents/Switch (10.1.0): - MaterialComponents/private/ThumbTrack - - MaterialComponents/Typography (10.0.0) - - MaterialComponentsCatalog (10.0.0): + - MaterialComponents/Typography (10.1.0) + - MaterialComponentsCatalog (10.1.0): - MaterialComponents - - MaterialComponentsUnitTests (10.0.0): + - MaterialComponentsUnitTests (10.1.0): - MaterialComponents DEPENDENCIES: @@ -127,9 +129,9 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - MaterialComponents: 1ba34edf996dbdf6acaea8b3051b5d78ab9d252f - MaterialComponentsCatalog: c665fdd39bff9621608cec8fe0a99e44ce8e7a13 - MaterialComponentsUnitTests: 66c55d81bb08daf37915f7142244bfeaa04a4776 + MaterialComponents: 65ac94f1904a9ddd867b95c2f3c55222943fd4fa + MaterialComponentsCatalog: 7d6fe07bb1e0967a4e84d6f804a846a14152e644 + MaterialComponentsUnitTests: 91fe0738eab0388318dc4b8be9c15790a35c2081 PODFILE CHECKSUM: 859f7856fc0fa049789dc17023b9f6f887fb1be9 diff --git a/components/ActivityIndicator/examples/ActivityIndicatorExample.m b/components/ActivityIndicator/examples/ActivityIndicatorExample.m new file mode 100644 index 00000000000..6a542c322e2 --- /dev/null +++ b/components/ActivityIndicator/examples/ActivityIndicatorExample.m @@ -0,0 +1,70 @@ +/* + Copyright 2016-present Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +#import "ActivityIndicatorExampleSupplemental.h" +#import "MaterialActivityIndicator.h" + +@interface ActivityIndicatorExample () + +@end + +@implementation ActivityIndicatorExample + +- (id)init { + self = [super init]; + if (self) { + self.title = @"Activity Indicator"; + self.view.backgroundColor = [UIColor whiteColor]; + + CGRect activityIndicator = CGRectMake(0, + 0, + kActivityIndicatorRadius * 2, + kActivityIndicatorRadius * 2); + _activityIndicator = [[MDCActivityIndicator alloc] initWithFrame:activityIndicator]; + _activityIndicator.delegate = self; + _activityIndicator.radius = kActivityIndicatorRadius; + _activityIndicator.strokeWidth = 8.f; + + _activityIndicator.autoresizingMask = + (UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | + UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin); + [self.view addSubview:_activityIndicator]; + + _activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; + _activityIndicator.progress = kActivityInitialProgress; + [_activityIndicator startAnimating]; + } + return self; +} + +@end + +@implementation ActivityIndicatorExample (CatalogByConvention) + +- (void)viewDidLoad { + [super viewDidLoad]; + [self setupExampleViews]; +} + +#pragma mark - MDCActivityIndicatorDelegate + +- (void)activityIndicatorAnimationDidFinish:(nonnull MDCActivityIndicator *)activityIndicator { + return; +} + +@end diff --git a/components/ActivityIndicator/examples/supplemental/ActivityIndicatorExampleSupplemental.h b/components/ActivityIndicator/examples/supplemental/ActivityIndicatorExampleSupplemental.h new file mode 100644 index 00000000000..b0d2762dc28 --- /dev/null +++ b/components/ActivityIndicator/examples/supplemental/ActivityIndicatorExampleSupplemental.h @@ -0,0 +1,33 @@ +/* IMPORTANT: + This file contains supplemental code used to populate the demos with dummy data or instructions. + It is not necessary to import this file to implement any Material Design Components. + */ + +#import + +#import "MaterialActivityIndicator.h" + +static const CGFloat kActivityIndicatorRadius = 72.f; +static const CGFloat kActivityInitialProgress = 0.6f; + +@class ActivityIndicatorExample; +@class MDCActivityIndicator; + +@interface ActivityIndicatorExample : UIViewController + +@property(nonatomic, strong) MDCActivityIndicator *activityIndicator; +@property(nonatomic, strong) UILabel *determinateSwitchLabel; +@property(nonatomic, strong) UILabel *onSwitchLabel; +@property(nonatomic, strong) UILabel *progressLabel; +@property(nonatomic, strong) UILabel *progressPercentLabel; +@property(nonatomic, strong) UISlider *slider; +@property(nonatomic, strong) UISwitch *onSwitch; +@property(nonatomic, strong) UISwitch *determinateSwitch; + +@end + +@interface ActivityIndicatorExample (Supplemental) + +- (void)setupExampleViews; + +@end diff --git a/components/ActivityIndicator/examples/supplemental/ActivityIndicatorExampleSupplemental.m b/components/ActivityIndicator/examples/supplemental/ActivityIndicatorExampleSupplemental.m new file mode 100644 index 00000000000..f65392ee5d5 --- /dev/null +++ b/components/ActivityIndicator/examples/supplemental/ActivityIndicatorExampleSupplemental.m @@ -0,0 +1,139 @@ +/* IMPORTANT: + This file contains supplemental code used to populate the examples with dummy data and/or + instructions. It is not necessary to import this file to implement any Material Design Components. + */ + +#import + +#import "ActivityIndicatorExampleSupplemental.h" +#import "MaterialTypography.h" + +@implementation ActivityIndicatorExample (CatalogByConvention) + ++ (NSArray *)catalogBreadcrumbs { + return @[ @"Activity Indicator", @"Activity Indicator" ]; +} + ++ (NSString *)catalogDescription { + return @"Activity Indicator is a visual indication of an app loading content. It can display how " + @"long an operation will take or visualize an unspecified wait time."; +} + ++ (BOOL)catalogIsPrimaryDemo { + return YES; +} + +@end + +@implementation ActivityIndicatorExample (Supplemental) + +- (void)setupExampleViews { + self.onSwitch = [[UISwitch alloc] init]; + [self.onSwitch setOn:YES]; + [self.onSwitch addTarget:self + action:@selector(didChangeOnSwitch:) + forControlEvents:UIControlEventValueChanged]; + [self.view addSubview:self.onSwitch]; + + self.onSwitchLabel = [[UILabel alloc] init]; + self.onSwitchLabel.text = @"Indicator Active"; + self.onSwitchLabel.font = [MDCTypography captionFont]; + self.onSwitchLabel.alpha = [MDCTypography captionFontOpacity]; + [self.onSwitchLabel sizeToFit]; + [self.view addSubview:self.onSwitchLabel]; + + self.determinateSwitch = [[UISwitch alloc] init]; + [self.determinateSwitch setOn:YES]; + [self.determinateSwitch addTarget:self + action:@selector(didChangeDeterminateSwitch:) + forControlEvents:UIControlEventValueChanged]; + [self.view addSubview:self.determinateSwitch]; + + self.determinateSwitchLabel = [[UILabel alloc] init]; + self.determinateSwitchLabel.text = @"Determinate Mode"; + self.determinateSwitchLabel.font = [MDCTypography captionFont]; + self.determinateSwitchLabel.alpha = [MDCTypography captionFontOpacity]; + [self.determinateSwitchLabel sizeToFit]; + [self.view addSubview:self.determinateSwitchLabel]; + + CGRect sliderFrame = CGRectMake(0, 0, 240, 27); + self.slider = [[UISlider alloc] initWithFrame:sliderFrame]; + self.slider.value = kActivityInitialProgress; + [self.slider addTarget:self + action:@selector(didChangeSliderValue:) + forControlEvents:UIControlEventValueChanged]; + [self.view addSubview:self.slider]; + + self.progressLabel = [[UILabel alloc] init]; + self.progressLabel.text = @"Progress"; + self.progressLabel.font = [MDCTypography captionFont]; + self.progressLabel.alpha = [MDCTypography captionFontOpacity]; + [self.progressLabel sizeToFit]; + [self.view addSubview:self.progressLabel]; + + self.progressPercentLabel = [[UILabel alloc] init]; + self.progressPercentLabel.text = + [NSString stringWithFormat:@"%.00f%%", kActivityInitialProgress * 100]; + self.progressPercentLabel.font = [MDCTypography captionFont]; + self.progressPercentLabel.alpha = [MDCTypography captionFontOpacity]; + self.progressPercentLabel.frame = CGRectMake(0, 0, 100, 16); + self.progressPercentLabel.textAlignment = NSTextAlignmentCenter; + [self.view addSubview:self.progressPercentLabel]; +} + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + + CGFloat navHeight = self.navigationController.navigationBar.frame.size.height; + if (self.view.frame.size.height > self.view.frame.size.width) { + self.activityIndicator.center = CGPointMake(CGRectGetMidX(self.view.frame), + CGRectGetMidY(self.view.frame) - navHeight * 2); + self.slider.center = CGPointMake(CGRectGetMidX(self.view.frame), 80); + self.progressLabel.center = CGPointMake(CGRectGetMidX(self.view.frame), 110); + self.onSwitch.center = CGPointMake(CGRectGetMidX(self.view.frame) - 50, + self.view.frame.size.height - 140); + self.onSwitchLabel.center = CGPointMake(CGRectGetMidX(self.view.frame) + 32, + self.view.frame.size.height - 140); + self.determinateSwitch.center = CGPointMake(CGRectGetMidX(self.view.frame) - 50, + self.view.frame.size.height - 90); + self.determinateSwitchLabel.center = CGPointMake(CGRectGetMidX(self.view.frame) + 38, + self.view.frame.size.height - 90); + } else { + self.activityIndicator.center = CGPointMake(CGRectGetMidX(self.view.frame) - 150, + CGRectGetMidY(self.view.frame) - 100); + self.slider.center = CGPointMake(CGRectGetMidX(self.view.frame) + 150, 20); + self.progressLabel.center = CGPointMake(CGRectGetMidX(self.view.frame) + 150, 50); + self.onSwitch.center = CGPointMake(CGRectGetMidX(self.view.frame) + 90, + self.view.frame.size.height - 140); + self.onSwitchLabel.center = CGPointMake(CGRectGetMidX(self.view.frame) + 172, + self.view.frame.size.height - 140); + self.determinateSwitch.center = CGPointMake(CGRectGetMidX(self.view.frame) + 90, + self.view.frame.size.height - 90); + self.determinateSwitchLabel.center = CGPointMake(CGRectGetMidX(self.view.frame) + 178, + self.view.frame.size.height - 90); + } + self.progressPercentLabel.center = self.activityIndicator.center; +} + +- (void)didChangeDeterminateSwitch:(UISwitch *)determinateSwitch { + if (determinateSwitch.on) { + self.activityIndicator.indicatorMode = MDCActivityIndicatorModeDeterminate; + } else { + self.activityIndicator.indicatorMode = MDCActivityIndicatorModeIndeterminate; + } +} + +- (void)didChangeOnSwitch:(UISwitch *)onSwitch { + if (onSwitch.on) { + [self.activityIndicator startAnimating]; + } else { + [self.activityIndicator stopAnimating]; + } +} + +- (void)didChangeSliderValue:(UISlider *)slider { + self.activityIndicator.progress = slider.value; + self.progressPercentLabel.text = [NSString stringWithFormat:@"%.00f%%", slider.value * 100]; +} + +@end diff --git a/components/ActivityIndicator/src/MDCActivityIndicator.h b/components/ActivityIndicator/src/MDCActivityIndicator.h new file mode 100644 index 00000000000..31760b65ae0 --- /dev/null +++ b/components/ActivityIndicator/src/MDCActivityIndicator.h @@ -0,0 +1,131 @@ +/* + Copyright 2016-present Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@protocol MDCActivityIndicatorDelegate; + +/** + Different operating modes for the activity indicator. + + This component can be used as a determinate progress indicator or an indeterminate activity + indicator. + + Default value is MDCActivityIndicatorModeIndeterminate. + */ +typedef NS_ENUM(NSInteger, MDCActivityIndicatorMode) { + /** Indeterminate indicators visualize an unspecified wait time. */ + MDCActivityIndicatorModeIndeterminate, + /** Determinate indicators display how long an operation will take. */ + MDCActivityIndicatorModeDeterminate, +}; + +/** + A Material Design activity indicator. + + The activity indicator is a circular spinner that shows progress of an operation. By default the + activity indicator assumes indeterminate progress of an unspecified length of time. In contrast to + a standard UIActivityIndicator, MDCActivityIndicator supports showing determinate progress and uses + custom Material Design animation for indeterminate progress. + + See https://www.google.com/design/spec/components/progress-activity.html + */ +IB_DESIGNABLE +@interface MDCActivityIndicator : UIView + +/** + The callback delegate. See @c MDCActivityIndicatorDelegate. + */ +@property(nonatomic, weak, nullable) id delegate; + +/** + Whether or not the activity indicator is currently animating. + */ +@property(nonatomic, assign, getter=isAnimating) BOOL animating; + +/** + Spinner radius width. Defaults to 12dp (24x24dp circle), constrained to range [8dp, 72dp]. The + spinner is centered in the view's bounds. If the bounds are smaller than the diameter of the + spinner, the spinner may be clipped when clipToBounds is true. + */ +@property(nonatomic, assign) CGFloat radius UI_APPEARANCE_SELECTOR; + +/** + Spinner stroke width. Defaults to 2dp. + */ +@property(nonatomic, assign) CGFloat strokeWidth UI_APPEARANCE_SELECTOR; + +/** + Show a faint ink track along the path of the indicator. Should be enabled when the activity + indicator wraps around another circular element, such as an avatar or a FAB. Defaults to NO. + */ +@property(nonatomic, assign) IBInspectable BOOL trackEnabled; + +/** + The mode of the activity indicator. Default is MDCActivityIndicatorModeIndeterminate. If + currently animating, it will animate the transition between the current mode to the new mode. + */ +@property(nonatomic, assign) IBInspectable MDCActivityIndicatorMode indicatorMode; + +/** + Set the mode of the activity indicator. If currently animating, it will animate the transition + between the current mode to the new mode. Default is MDCActivityIndicatorModeIndeterminate with no + animation. + */ +- (void)setIndicatorMode:(MDCActivityIndicatorMode)mode animated:(BOOL)animated; + +/** + Progress is the extent to which the activity indicator circle is drawn to completion when + indicatorMode is MDCActivityIndicatorModeDeterminate. Progress is drawn clockwise to complete a + circle. Valid range is between [0-1]. Default is zero. 0.5 progress is half the circle. The + transitions between progress levels are animated. + */ +@property(nonatomic, assign) IBInspectable float progress; + +/** + The array of colors that are cycled through when animating the spinner. Populated with default + colors of blue, red, yellow and green on initialization. An empty array results in a blue spinner + with no color cycling. + */ +@property(nonatomic, copy, nonnull) NSArray *cycleColors UI_APPEARANCE_SELECTOR; + +/** + Starts the animated activity indicator. Does nothing if the spinner is already animating. + */ +- (void)startAnimating; + +/** + Stops the animated activity indicator with a short opacity and stroke width animation. Does nothing + if the spinner is not animating. + */ +- (void)stopAnimating; + +@end + +/** + Delegate protocol for the MDCActivityIndicator. + */ +@protocol MDCActivityIndicatorDelegate + +/** + When stop is called, the spinner gracefully animates out using opacity and stroke width. + This method is called after that fade-out animation completes. + + @param activityIndicator Caller + */ +- (void)activityIndicatorAnimationDidFinish:(nonnull MDCActivityIndicator *)activityIndicator; + +@end diff --git a/components/ActivityIndicator/src/MDCActivityIndicator.m b/components/ActivityIndicator/src/MDCActivityIndicator.m new file mode 100644 index 00000000000..d2f15e0065a --- /dev/null +++ b/components/ActivityIndicator/src/MDCActivityIndicator.m @@ -0,0 +1,800 @@ +/* + Copyright 2016-present Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MDCActivityIndicator.h" + +static const NSInteger kMDCActivityIndicatorTotalDetentCount = 5; +static const NSTimeInterval kMDCActivityIndicatorAnimateOutDuration = 0.1f; +static const NSTimeInterval kMDCActivityIndicatorPointCycleDuration = 4.0f / 3.0f; +static const NSTimeInterval kMDCActivityIndicatorPointCycleMinimumVariableDuration = + kMDCActivityIndicatorPointCycleDuration / 8; +static const CGFloat kCycleRotation = 3.0f / 2.0f; +static const CGFloat kOuterRotationIncrement = (1.0f / kMDCActivityIndicatorTotalDetentCount) * + (CGFloat)M_PI; +static const CGFloat kSpinnerRadius = 12.f; +static const CGFloat kStrokeLength = 0.75f; + +/** + Total rotation (outer rotation + stroke rotation) per _cycleCount. One turn is 2.0f. + */ +static const CGFloat kSingleCycleRotation = 2 * kStrokeLength + kCycleRotation + 1.0f / + kMDCActivityIndicatorTotalDetentCount; + +/* + States for the internal state machine. The states represent the last animation completed. + It provides information required to select the next animation. + */ +typedef NS_ENUM(NSInteger, MDCActivityIndicatorState) { + MDCActivityIndicatorStateIndeterminate, + MDCActivityIndicatorStateTransitionToDeterminate, + MDCActivityIndicatorStateDeterminate, + MDCActivityIndicatorStateTransitionToIndeterminate, +}; + +@interface MDCActivityIndicator () + +/** + The minimum stroke difference to use when collapsing the stroke to a dot. Based on current + radius and stroke width. + */ +@property(nonatomic, assign, readonly) CGFloat minStrokeDifference; + +/** + The current color count for the spinner. Subclasses can change this value to start the spinner at + a different color. + */ +@property(nonatomic, assign) NSUInteger currentColorCount; + +/** + The current cycle count. + */ +@property(nonatomic, assign, readonly) NSInteger cycleCount; + +/** + The cycle index at which to start the activity spinner animation. Default is 0, which corresponds + to the top of the spinner (12 o'clock position). Spinner cycle indices are based on a 5-point + star. + */ +@property(nonatomic, assign) NSInteger cycleStartIndex; + +/** + The outer layer that handles cycle rotations and houses the stroke layer. + */ +@property(nonatomic, strong, readonly, nullable) CALayer *outerRotationLayer; + +/** + The shape layer that handles the animating stroke. + */ +@property(nonatomic, strong, readonly, nullable) CAShapeLayer *strokeLayer; + +/** + The shape layer that shows a faint, circular track along the path of the stroke layer. Enabled + via the trackEnabled property. + */ +@property(nonatomic, strong, readonly, nullable) CAShapeLayer *trackLayer; + +@end + +@implementation MDCActivityIndicator { + BOOL _animatingOut; + BOOL _animationsAdded; + BOOL _animationInProgress; + BOOL _backgrounded; + BOOL _cycleInProgress; + CGFloat _currentProgress; + CGFloat _lastProgress; + MDCActivityIndicatorState _lastCompletedState; +} + +#pragma mark - Init + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self commonInitializer]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + [self commonInitializer]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + [self applyPropertiesWithoutAnimation:^{ + // Resize and recenter rotation layer. + _outerRotationLayer.bounds = self.bounds; + _outerRotationLayer.position = + CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2); + + _strokeLayer.bounds = _outerRotationLayer.bounds; + _strokeLayer.position = _outerRotationLayer.position; + + [self updateStrokePath]; + }]; +} + +- (void)commonInitializer { + // Register notifications for foreground and background if needed. + [self registerForegroundAndBackgroundNotificationObserversIfNeeded]; + + _cycleStartIndex = 0; + _indicatorMode = MDCActivityIndicatorModeIndeterminate; + + // Property defaults. + _radius = kSpinnerRadius; + _strokeWidth = 2.0f; + + // Colors. + _cycleColors = [MDCActivityIndicator defaultColors]; + _currentColorCount = 0; + + // Track layer. + _trackLayer = [CAShapeLayer layer]; + _trackLayer.lineWidth = _strokeWidth; + _trackLayer.fillColor = [UIColor clearColor].CGColor; + [self.layer addSublayer:_trackLayer]; + _trackLayer.hidden = YES; + + // Rotation layer. + _outerRotationLayer = [CALayer layer]; + [self.layer addSublayer:_outerRotationLayer]; + + // Stroke layer. + _strokeLayer = [CAShapeLayer layer]; + _strokeLayer.lineWidth = _strokeWidth; + _strokeLayer.fillColor = [UIColor clearColor].CGColor; + _strokeLayer.strokeStart = 0; + _strokeLayer.strokeEnd = 0; + [_outerRotationLayer addSublayer:_strokeLayer]; +} + +#pragma mark - UIView + +- (void)willMoveToWindow:(UIWindow *)newWindow { + // If the activity indicator is removed from the window, we should + // immediately stop animating, otherwise it will start chewing up CPU. + if (!newWindow) { + [self actuallyStopAnimating]; + } else if (_animating && !_backgrounded) { + [self actuallyStartAnimating]; + } +} + +#pragma mark - Public methods + +- (void)startAnimating { + if (_animatingOut) { + [self removeAnimations]; + } + + if (_animating) { + return; + } + + _animating = YES; + + if (self.window && !_backgrounded) { + [self actuallyStartAnimating]; + } +} + +- (void)stopAnimating { + if (!_animating) { + return; + } + + _animating = NO; + + [self animateOut]; +} + +- (void)stopAnimatingImmediately { + if (!_animating) { + return; + } + + _animating = NO; + + [self actuallyStopAnimating]; + [_delegate activityIndicatorAnimationDidFinish:self]; +} + +- (void)resetStrokeColor { + _currentColorCount = 0; + + [self updateStrokeColor]; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + _strokeLayer.strokeColor = strokeColor.CGColor; + _trackLayer.strokeColor = [strokeColor colorWithAlphaComponent:0.3f].CGColor; +} + +- (void)setIndicatorMode:(MDCActivityIndicatorMode)indicatorMode { + if (_indicatorMode == indicatorMode) { + return; + } + _indicatorMode = indicatorMode; + if (_animating && !_animationInProgress) { + switch (indicatorMode) { + case MDCActivityIndicatorModeDeterminate: + [self addTransitionToDeterminateCycle]; + break; + case MDCActivityIndicatorModeIndeterminate: + [self addTransitionToIndeterminateCycle]; + break; + } + } +} + +- (void)setIndicatorMode:(MDCActivityIndicatorMode)mode animated:(BOOL)animated { + [self setIndicatorMode:mode]; +} + +- (void)setProgress:(float)progress { + _progress = MAX(0.0f, MIN(progress, 1.0f)); + if (_progress == _currentProgress) { + return; + } + if (_animating && !_animationInProgress) { + switch (_indicatorMode) { + case MDCActivityIndicatorModeDeterminate: + // Currently animating the determinate mode but no animation queued. + [self addProgressAnimation]; + break; + case MDCActivityIndicatorModeIndeterminate: + break; + } + } +} + +#pragma mark - Properties + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + _strokeWidth = strokeWidth; + _strokeLayer.lineWidth = _strokeWidth; + _trackLayer.lineWidth = _strokeWidth; + + [self updateStrokePath]; +} + +- (void)setSpinnerRadius:(CGFloat)spinnerRadius { + // Constrain radius to range [8dp, 72dp]. + _radius = MIN(MAX(spinnerRadius, 8.0f), 72.0f); + + [self updateStrokePath]; +} + +- (void)setTrackEnabled:(BOOL)trackEnabled { + _trackEnabled = trackEnabled; + + _trackLayer.hidden = !_trackEnabled; +} + +#pragma mark - Private methods + +/** + If this class is not being run in an extension, register for foreground changes and initialize + the app background state in case UI is created when the app is backgrounded. (Extensions always + return UIApplicationStateBackground for |[UIApplication sharedApplication].applicationState|.) + */ +- (void)registerForegroundAndBackgroundNotificationObserversIfNeeded { + if ([[self class] isExtension]) { + return; + } + + _backgrounded = + [UIApplication sharedApplication].applicationState == UIApplicationStateBackground; + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(controlAnimatingOnForegroundChange:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(controlAnimatingOnForegroundChange:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +} + +- (void)controlAnimatingOnForegroundChange:(NSNotification *)notification { + // Stop or restart animating if the app has a foreground change. + _backgrounded = + [notification.name isEqualToString:UIApplicationDidEnterBackgroundNotification]; + if (_animating) { + if (_backgrounded) { + [self actuallyStopAnimating]; + } else if (self.window) { + [self actuallyStartAnimating]; + } + } +} + +- (void)actuallyStartAnimating { + if (_animationsAdded) { + return; + } + _animationsAdded = YES; + _cycleCount = _cycleStartIndex; + + [self applyPropertiesWithoutAnimation:^{ + _strokeLayer.strokeStart = 0.0f; + _strokeLayer.strokeEnd = 0.001f; + _strokeLayer.lineWidth = _strokeWidth; + _trackLayer.lineWidth = _strokeWidth; + + [self resetStrokeColor]; + [self updateStrokePath]; + }]; + + switch (_indicatorMode) { + case MDCActivityIndicatorModeIndeterminate: + [self addStrokeRotationCycle]; + break; + case MDCActivityIndicatorModeDeterminate: + [self addProgressAnimation]; + break; + } +} + +- (void)actuallyStopAnimating { + if (!_animationsAdded) { + return; + } + + [self removeAnimations]; + [self applyPropertiesWithoutAnimation:^{ + _strokeLayer.strokeStart = 0.0f; + _strokeLayer.strokeEnd = 0.0f; + }]; +} + +- (void)updateStrokePath { + CGFloat offsetRadius = _radius - _strokeLayer.lineWidth / 2.0f; + UIBezierPath *strokePath = [UIBezierPath bezierPathWithArcCenter:_strokeLayer.position + radius:offsetRadius + startAngle:-1.0f * (CGFloat)M_PI_2 + endAngle:3.0f * (CGFloat)M_PI_2 + clockwise:YES]; + _strokeLayer.path = strokePath.CGPath; + _trackLayer.path = strokePath.CGPath; + + _minStrokeDifference = _strokeLayer.lineWidth / ((CGFloat)M_PI * 2 * _radius); +} + +- (void)updateStrokeColor { + if (_cycleColors.count > 0) { + [self setStrokeColor:_cycleColors[_currentColorCount]]; + } else { + [self setStrokeColor:[MDCActivityIndicator defaultColors][0]]; + } +} + +- (void)addStrokeRotationCycle { + if (_animationInProgress) { + return; + } + + [CATransaction begin]; + { + [CATransaction setCompletionBlock:^{ + _lastCompletedState = MDCActivityIndicatorStateIndeterminate; + [self strokeRotationCycleFinished]; + }]; + + // Outer 5-point star detent rotation. + CABasicAnimation *outerRotationAnimation = + [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + outerRotationAnimation.duration = kMDCActivityIndicatorPointCycleDuration; + outerRotationAnimation.fromValue = @(kOuterRotationIncrement * _cycleCount); + outerRotationAnimation.toValue = @(kOuterRotationIncrement * (_cycleCount + 1)); + outerRotationAnimation.fillMode = kCAFillModeForwards; + outerRotationAnimation.removedOnCompletion = NO; + [_outerRotationLayer addAnimation:outerRotationAnimation forKey:@"transform.rotation.z"]; + + // Stroke rotation. + CGFloat startRotation = _cycleCount * (CGFloat)M_PI; + CGFloat endRotation = startRotation + kCycleRotation * (CGFloat)M_PI; + + CABasicAnimation *strokeRotationAnimation = + [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + strokeRotationAnimation.duration = kMDCActivityIndicatorPointCycleDuration; + strokeRotationAnimation.fromValue = @(startRotation); + strokeRotationAnimation.toValue = @(endRotation); + strokeRotationAnimation.fillMode = kCAFillModeForwards; + strokeRotationAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeRotationAnimation forKey:@"transform.rotation.z"]; + + // Stroke start. + CABasicAnimation *strokeStartPathAnimation = + [CABasicAnimation animationWithKeyPath:@"strokeStart"]; + strokeStartPathAnimation.duration = kMDCActivityIndicatorPointCycleDuration / 2; + // It is always critical to convertTime:fromLayer: for animations, since changes to layer.speed + // on this layer or parent layers will alter the offset of beginTime. + CFTimeInterval currentTime = [_strokeLayer convertTime:CACurrentMediaTime() fromLayer:nil]; + strokeStartPathAnimation.beginTime = currentTime + kMDCActivityIndicatorPointCycleDuration / 2; + strokeStartPathAnimation.fromValue = @(0.0f); + strokeStartPathAnimation.toValue = @(kStrokeLength); + strokeStartPathAnimation.timingFunction = [self materialEaseInOut]; + strokeStartPathAnimation.fillMode = kCAFillModeBoth; + strokeStartPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeStartPathAnimation forKey:@"strokeStart"]; + + // Stroke end. + CABasicAnimation *strokeEndPathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; + strokeEndPathAnimation.duration = kMDCActivityIndicatorPointCycleDuration * + ABS(_lastProgress - _currentProgress); + // Ensure the stroke never completely disappears on start by animating from non-zero start and + // to a value slightly larger than the strokeStart's final value. + strokeEndPathAnimation.fromValue = @(_minStrokeDifference); + strokeEndPathAnimation.toValue = @(kStrokeLength + _minStrokeDifference); + strokeEndPathAnimation.timingFunction = [self materialEaseInOut]; + strokeEndPathAnimation.fillMode = kCAFillModeBoth; + strokeEndPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeEndPathAnimation forKey:@"strokeEnd"]; + } + [CATransaction commit]; + + _animationInProgress = YES; +} + +- (void)addTransitionToIndeterminateCycle { + if (_animationInProgress) { + return; + } + // Find the nearest cycle to transition through. + NSInteger nearestCycle = 0; + CGFloat nearestDistance = CGFLOAT_MAX; + const CGFloat normalizedProgress = MAX(_lastProgress - _minStrokeDifference, 0.0f); + for (NSInteger cycle = 0; cycle < kMDCActivityIndicatorTotalDetentCount; cycle++) { + const CGFloat currentRotation = [self normalizedRotationForCycle:cycle]; + if (currentRotation >= normalizedProgress) { + if (nearestDistance >= (currentRotation - normalizedProgress)) { + nearestDistance = currentRotation - normalizedProgress; + nearestCycle = cycle; + } + } + } + + if (nearestCycle == 0 && _lastProgress <= _minStrokeDifference) { + // Special case for 0% progress. + _cycleCount = nearestCycle; + _lastCompletedState = MDCActivityIndicatorStateTransitionToIndeterminate; + [self strokeRotationCycleFinished]; + return; + } + + _cycleCount = nearestCycle; + + CGFloat targetRotation = [self normalizedRotationForCycle:nearestCycle]; + if (targetRotation <= 0.001f) { + targetRotation = 1.0f; + } + CGFloat normalizedDuration = 2 * (targetRotation + _currentProgress) / kSingleCycleRotation * + (CGFloat)kMDCActivityIndicatorPointCycleDuration; + CGFloat strokeEndTravelDistance = targetRotation - _currentProgress + _minStrokeDifference; + CGFloat totalDistance = targetRotation + strokeEndTravelDistance; + CGFloat strokeStartDuration = MAX(normalizedDuration * targetRotation / totalDistance, + (CGFloat)kMDCActivityIndicatorPointCycleMinimumVariableDuration); + CGFloat strokeEndDuration = MAX(normalizedDuration * strokeEndTravelDistance / totalDistance, + (CGFloat)kMDCActivityIndicatorPointCycleMinimumVariableDuration); + + [CATransaction begin]; + { + [CATransaction setCompletionBlock:^{ + _lastCompletedState = MDCActivityIndicatorStateTransitionToIndeterminate; + [self strokeRotationCycleFinished]; + }]; + + // Stroke start. + CABasicAnimation *strokeStartPathAnimation = + [CABasicAnimation animationWithKeyPath:@"strokeStart"]; + strokeStartPathAnimation.duration = strokeStartDuration; + CFTimeInterval currentTime = [_strokeLayer convertTime:CACurrentMediaTime() fromLayer:nil]; + strokeStartPathAnimation.beginTime = currentTime + strokeEndDuration; + strokeStartPathAnimation.fromValue = @(0.0f); + strokeStartPathAnimation.toValue = @(targetRotation); + strokeStartPathAnimation.timingFunction = [self materialEaseInOut]; + ; + strokeStartPathAnimation.fillMode = kCAFillModeBoth; + strokeStartPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeStartPathAnimation forKey:@"strokeStart"]; + + // Stroke end. + CABasicAnimation *strokeEndPathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; + strokeEndPathAnimation.duration = strokeEndDuration; + // Ensure the stroke never completely disappears on start by animating from non-zero start and + // to a value slightly larger than the strokeStart's final value. + strokeEndPathAnimation.fromValue = @(_currentProgress); + strokeEndPathAnimation.toValue = @(targetRotation + _minStrokeDifference); + strokeEndPathAnimation.timingFunction = [self materialEaseInOut]; + strokeEndPathAnimation.fillMode = kCAFillModeBoth; + strokeEndPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeEndPathAnimation forKey:@"strokeEnd"]; + } + [CATransaction commit]; + + _animationInProgress = YES; +} + +- (void)addTransitionToDeterminateCycle { + if (_animationInProgress) { + return; + } + if (!_cycleCount) { + // The animation period is complete: no need for transition. + [_strokeLayer removeAllAnimations]; + [_outerRotationLayer removeAllAnimations]; + // Necessary for transition from indeterminate to determinate when cycle == 0. + _currentProgress = 0.0f; + _lastProgress = _currentProgress; + _lastCompletedState = MDCActivityIndicatorStateTransitionToDeterminate; + [self strokeRotationCycleFinished]; + } else { + _currentProgress = MAX(_progress, _minStrokeDifference); + + CGFloat rotationDelta = 1.0f - [self normalizedRotationForCycle:_cycleCount]; + + // Change the duration relative to the distance in order to keep same relative speed. + CGFloat duration = 2.0f * (rotationDelta + _currentProgress) / kSingleCycleRotation * (CGFloat)kMDCActivityIndicatorPointCycleDuration; + + duration = MAX(duration, + (CGFloat)kMDCActivityIndicatorPointCycleMinimumVariableDuration); + [CATransaction begin]; + { + [CATransaction setCompletionBlock:^{ + _lastCompletedState = MDCActivityIndicatorStateTransitionToDeterminate; + [self strokeRotationCycleFinished]; + }]; + + // Outer 5-point star detent rotation. Required for passing from transitionToIndeterminate to + // transitionToDeterminate. + CABasicAnimation *outerRotationAnimation = + [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + outerRotationAnimation.duration = duration; + outerRotationAnimation.fromValue = @(kOuterRotationIncrement * _cycleCount); + outerRotationAnimation.toValue = @(kOuterRotationIncrement * _cycleCount); + outerRotationAnimation.fillMode = kCAFillModeForwards; + outerRotationAnimation.removedOnCompletion = NO; + [_outerRotationLayer addAnimation:outerRotationAnimation forKey:@"transform.rotation.z"]; + + // Stroke rotation. + CGFloat startRotation = _cycleCount * (CGFloat)M_PI; + CGFloat endRotation = startRotation + rotationDelta * 2.0f * (CGFloat)M_PI; + + CABasicAnimation *strokeRotationAnimation = + [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + strokeRotationAnimation.duration = duration; + strokeRotationAnimation.fromValue = @(startRotation); + strokeRotationAnimation.toValue = @(endRotation); + strokeRotationAnimation.fillMode = kCAFillModeForwards; + strokeRotationAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeRotationAnimation forKey:@"transform.rotation.z"]; + + // Stroke start. + CABasicAnimation *strokeStartPathAnimation = + [CABasicAnimation animationWithKeyPath:@"strokeStart"]; + strokeStartPathAnimation.duration = duration; + // It is always critical to convertTime:fromLayer: for animations, since changes to + // layer.speed on this layer or parent layers will alter the offset of beginTime. + CFTimeInterval currentTime = [_strokeLayer convertTime:CACurrentMediaTime() fromLayer:nil]; + strokeStartPathAnimation.beginTime = currentTime; + strokeStartPathAnimation.fromValue = @(0.0f); + strokeStartPathAnimation.toValue = @(0.0f); + strokeStartPathAnimation.timingFunction = [self materialEaseInOut]; + strokeStartPathAnimation.fillMode = kCAFillModeBoth; + strokeStartPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeStartPathAnimation forKey:@"strokeStart"]; + + // Stroke end. + CABasicAnimation *strokeEndPathAnimation = + [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; + strokeEndPathAnimation.duration = duration; + // Ensure the stroke never completely disappears on start by animating from non-zero start and + // to a value slightly larger than the strokeStart's final value. + strokeEndPathAnimation.fromValue = @(_minStrokeDifference); + strokeEndPathAnimation.toValue = @(_currentProgress); + strokeEndPathAnimation.timingFunction = [self materialEaseInOut]; + strokeEndPathAnimation.fillMode = kCAFillModeBoth; + strokeEndPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeEndPathAnimation forKey:@"strokeEnd"]; + } + [CATransaction commit]; + + _animationInProgress = YES; + _lastProgress = _currentProgress; + } +} + +- (CAMediaTimingFunction *)materialEaseInOut { + // This curve is slow both at the beginning and end. + // Visualization of curve http://cubic-bezier.com/#.4,0,.2,1 + return [[CAMediaTimingFunction alloc] initWithControlPoints:0.4f:0.0f:0.2f:1.0f]; +} + +- (void)addProgressAnimation { + if (_animationInProgress) { + return; + } + + _currentProgress = MAX(_progress, _minStrokeDifference); + + [CATransaction begin]; + { + [CATransaction setCompletionBlock:^{ + _lastCompletedState = MDCActivityIndicatorStateDeterminate; + [self strokeRotationCycleFinished]; + }]; + + // Stroke end. + CABasicAnimation *strokeEndPathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; + strokeEndPathAnimation.duration = kMDCActivityIndicatorPointCycleDuration / 2; + strokeEndPathAnimation.fromValue = @(_lastProgress); + strokeEndPathAnimation.toValue = @(_currentProgress); + strokeEndPathAnimation.timingFunction = [self materialEaseInOut]; + strokeEndPathAnimation.fillMode = kCAFillModeBoth; + strokeEndPathAnimation.removedOnCompletion = NO; + [_strokeLayer addAnimation:strokeEndPathAnimation forKey:@"strokeEnd"]; + } + + [CATransaction commit]; + + _lastProgress = _currentProgress; + _animationInProgress = YES; +} + +- (void)strokeRotationCycleFinished { + _animationInProgress = NO; + + if (!_animationsAdded) { + return; + } + if (_lastCompletedState == MDCActivityIndicatorStateIndeterminate) { + if (_cycleColors.count > 0) { + _currentColorCount = (_currentColorCount + 1) % _cycleColors.count; + [self updateStrokeColor]; + } + _cycleCount = (_cycleCount + 1) % kMDCActivityIndicatorTotalDetentCount; + } + + switch (_indicatorMode) { + case MDCActivityIndicatorModeDeterminate: + switch (_lastCompletedState) { + case MDCActivityIndicatorStateDeterminate: + case MDCActivityIndicatorStateTransitionToDeterminate: + [self addProgressAnimationIfRequired]; + break; + case MDCActivityIndicatorStateIndeterminate: + case MDCActivityIndicatorStateTransitionToIndeterminate: + [self addTransitionToDeterminateCycle]; + break; + } + break; + case MDCActivityIndicatorModeIndeterminate: + switch (_lastCompletedState) { + case MDCActivityIndicatorStateDeterminate: + case MDCActivityIndicatorStateTransitionToDeterminate: + [self addTransitionToIndeterminateCycle]; + break; + case MDCActivityIndicatorStateIndeterminate: + case MDCActivityIndicatorStateTransitionToIndeterminate: + [self addStrokeRotationCycle]; + break; + } + break; + } +} + +- (void)addProgressAnimationIfRequired { + if (_indicatorMode == MDCActivityIndicatorModeDeterminate) { + if (MAX(_progress, _minStrokeDifference) != _currentProgress) { + // The values were changes in the while animating or animation is starting. + [self addProgressAnimation]; + } + } +} + +/** + Rotation that a given cycle has. Represented between 0.0f (cycle has no rotation) and 1.0f. + */ +- (CGFloat)normalizedRotationForCycle:(NSInteger)cycle { + CGFloat cycleRotation = cycle * kSingleCycleRotation / 2.0f; + return cycleRotation - ((NSInteger)cycleRotation); +} + +- (void)animateOut { + _animatingOut = YES; + + [CATransaction begin]; + + [CATransaction setCompletionBlock:^{ + if (_animatingOut) { + [self removeAnimations]; + [_delegate activityIndicatorAnimationDidFinish:self]; + } + }]; + [CATransaction setAnimationDuration:kMDCActivityIndicatorAnimateOutDuration]; + + _strokeLayer.lineWidth = 0; + _trackLayer.lineWidth = 0; + + [CATransaction commit]; +} + +- (void)removeAnimations { + _animationsAdded = NO; + _animatingOut = NO; + [_strokeLayer removeAllAnimations]; + [_outerRotationLayer removeAllAnimations]; + + // Reset cycle count to 0 rather than cycleStart to reflect default starting position (top). + _cycleCount = 0; + // However _animationInProgress represents the CATransaction that hasn't finished, so we leave it + // alone here. +} + +/** Returns whether this class is being executed in an extension or not. */ ++ (BOOL)isExtension { + return [[[NSBundle mainBundle] executablePath] rangeOfString:@".appex/"].location != NSNotFound; +} + ++ (CGFloat)defaultHeight { + return kSpinnerRadius * 2.f; +} + +- (void)applyPropertiesWithoutAnimation:(void (^)(void))setPropBlock { + [CATransaction begin]; + + // Disable implicit CALayer animations + [CATransaction setDisableActions:YES]; + setPropBlock(); + + [CATransaction commit]; +} + ++ (NSArray *)defaultColors { + static NSArray *defaultColors; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultColors = + @[ [[UIColor alloc] initWithRed:0.129f green:0.588f blue:0.953f alpha:1], + [[UIColor alloc] initWithRed:0.957f + green:0.263f + blue:0.212f + alpha:1], + [[UIColor alloc] initWithRed:1.0f + green:0.922f + blue:0.231f + alpha:1], + [[UIColor alloc] initWithRed:0.298f + green:0.686f + blue:0.314f + alpha:1] ]; + }); + return defaultColors; +} + +@end diff --git a/components/ActivityIndicator/src/MaterialActivityIndicator.h b/components/ActivityIndicator/src/MaterialActivityIndicator.h new file mode 100644 index 00000000000..6789a2dd347 --- /dev/null +++ b/components/ActivityIndicator/src/MaterialActivityIndicator.h @@ -0,0 +1,17 @@ +/* + Copyright 2016-present Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MDCActivityIndicator.h" diff --git a/components/AppBar/src/MDCAppBar.m b/components/AppBar/src/MDCAppBar.m index 496e9218495..9cedfa90022 100644 --- a/components/AppBar/src/MDCAppBar.m +++ b/components/AppBar/src/MDCAppBar.m @@ -164,11 +164,24 @@ - (UIBarButtonItem *)backButtonItem { if (!backBarButtonItem) { UIImage *backButtonImage = [UIImage imageWithContentsOfFile:[MDCIcons pathFor_ic_arrow_back]]; backButtonImage = [backButtonImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + if (self.navigationBar.layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) { +#if defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0 + if ([backButtonImage + respondsToSelector:@selector(imageFlippedForRightToLeftLayoutDirection)]) { + backButtonImage = [backButtonImage imageFlippedForRightToLeftLayoutDirection]; + } +#else + backButtonImage = [UIImage imageWithCGImage:backButtonImage.CGImage + scale:backButtonImage.scale + orientation:UIImageOrientationUpMirrored]; +#endif + } backBarButtonItem = [[UIBarButtonItem alloc] initWithImage:backButtonImage style:UIBarButtonItemStyleDone target:self action:@selector(didTapBackButton:)]; } + backBarButtonItem.accessibilityIdentifier = @"back_bar_button"; return backBarButtonItem; } diff --git a/components/ButtonBar/examples/ButtonBarTypicalUseExample.swift b/components/ButtonBar/examples/ButtonBarTypicalUseExample.swift index d9a050d537a..3507cc33fbb 100644 --- a/components/ButtonBar/examples/ButtonBarTypicalUseExample.swift +++ b/components/ButtonBar/examples/ButtonBarTypicalUseExample.swift @@ -32,14 +32,14 @@ class ButtonBarTypicalUseSwiftExample: UIViewController { title: "Action", style: ignored, target: self, - action: "didTapActionButton:" + action: #selector(didTapActionButton) ) let secondActionItem = UIBarButtonItem( title: "Second action", style: ignored, target: self, - action: "didTapActionButton:" + action: #selector(didTapActionButton) ) let items = [actionItem, secondActionItem] diff --git a/components/Buttons/examples/ButtonsSimpleExampleSwiftViewController.swift b/components/Buttons/examples/ButtonsSimpleExampleSwiftViewController.swift index c048647f06b..47e3b1f99d1 100644 --- a/components/Buttons/examples/ButtonsSimpleExampleSwiftViewController.swift +++ b/components/Buttons/examples/ButtonsSimpleExampleSwiftViewController.swift @@ -29,7 +29,7 @@ class ButtonsSimpleExampleSwiftViewController: UIViewController { raisedButton.setTitle("Tap Me Too", forState: .Normal) raisedButton.sizeToFit() raisedButton.translatesAutoresizingMaskIntoConstraints = false - raisedButton.addTarget(self, action: "tap:", forControlEvents: .TouchUpInside) + raisedButton.addTarget(self, action: #selector(tap), forControlEvents: .TouchUpInside) self.view.addSubview(raisedButton) let flatButton = MDCFlatButton() @@ -37,14 +37,14 @@ class ButtonsSimpleExampleSwiftViewController: UIViewController { flatButton.setTitle("Touch me", forState: .Normal) flatButton.sizeToFit() flatButton.translatesAutoresizingMaskIntoConstraints = false - flatButton.addTarget(self, action: "tap:", forControlEvents: .TouchUpInside) + flatButton.addTarget(self, action: #selector(tap), forControlEvents: .TouchUpInside) self.view.addSubview(flatButton) let floatingButton = MDCFloatingButton() floatingButton.setTitle("+", forState: .Normal) floatingButton.sizeToFit() floatingButton.translatesAutoresizingMaskIntoConstraints = false - floatingButton.addTarget(self, action: "tap:", forControlEvents: .TouchUpInside) + floatingButton.addTarget(self, action: #selector(tap), forControlEvents: .TouchUpInside) self.view.addSubview(floatingButton) let views = [ diff --git a/components/Buttons/examples/ButtonsStoryboardAndProgrammatic.swift b/components/Buttons/examples/ButtonsStoryboardAndProgrammatic.swift index d0fbe341cf3..3504eacb7d6 100644 --- a/components/Buttons/examples/ButtonsStoryboardAndProgrammatic.swift +++ b/components/Buttons/examples/ButtonsStoryboardAndProgrammatic.swift @@ -49,20 +49,20 @@ class ButtonsStoryboardAndProgrammaticController: UIViewController { raisedButton.setTitle("Programmatic", forState: .Normal) raisedButton.sizeToFit() raisedButton.translatesAutoresizingMaskIntoConstraints = false - raisedButton.addTarget(self, action: "tap:", forControlEvents: .TouchUpInside) + raisedButton.addTarget(self, action: #selector(tap), forControlEvents: .TouchUpInside) self.view.addSubview(raisedButton) flatButton.customTitleColor = UIColor.grayColor() flatButton.setTitle("Programmatic", forState: .Normal) flatButton.sizeToFit() flatButton.translatesAutoresizingMaskIntoConstraints = false - flatButton.addTarget(self, action: "tap:", forControlEvents: .TouchUpInside) + flatButton.addTarget(self, action: #selector(tap), forControlEvents: .TouchUpInside) self.view.addSubview(flatButton) floatingButton.setTitle("+", forState: .Normal) floatingButton.sizeToFit() floatingButton.translatesAutoresizingMaskIntoConstraints = false - floatingButton.addTarget(self, action: "tap:", forControlEvents: .TouchUpInside) + floatingButton.addTarget(self, action: #selector(tap), forControlEvents: .TouchUpInside) self.view.addSubview(floatingButton) let views = [ diff --git a/components/Collections/src/MDCCollectionViewController.m b/components/Collections/src/MDCCollectionViewController.m index 1e2fe5eb906..bd900cb4beb 100644 --- a/components/Collections/src/MDCCollectionViewController.m +++ b/components/Collections/src/MDCCollectionViewController.m @@ -48,7 +48,7 @@ @implementation MDCCollectionViewController { - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout { self = [super initWithCollectionViewLayout:layout]; if (self) { - [self commonMDCCollectionViewControllerInit:self.collectionViewLayout]; + [self commonMDCCollectionViewControllerInit:layout]; } return self; } diff --git a/components/FontDiskLoader/README.md b/components/FontDiskLoader/README.md index 05e14dc2459..3cd3a45728e 100644 --- a/components/FontDiskLoader/README.md +++ b/components/FontDiskLoader/README.md @@ -13,11 +13,9 @@ Registers a single custom font asset from disk diff --git a/components/FontDiskLoader/src/MDCFontDiskLoader.h b/components/FontDiskLoader/src/MDCFontDiskLoader.h index 71409c789aa..7b179f87c25 100644 --- a/components/FontDiskLoader/src/MDCFontDiskLoader.h +++ b/components/FontDiskLoader/src/MDCFontDiskLoader.h @@ -16,8 +16,16 @@ #import -/** Register and load a custom font resource. */ -@interface MDCFontDiskLoader : NSObject +/** + Register and load a custom font resource. + + This class provides a convenience layer on top of CoreText APIs. Registration occurs by @c fileURL, + therefore registration state is shared across all instances of MDCFontDiskLoader objects. For + example if two MDCFontDiskLoader objects have the same fileURL, calling @c registerFont one will + also alter the state of the second MDCFontDiskLoader object. The same holds true for + @c unregisterFont. + */ +@interface MDCFontDiskLoader : NSObject #pragma mark Creating a font resource @@ -58,22 +66,46 @@ /** Attempts to register the font. + All instances of MDCFontDiskLoader with the same fontURL will reflect changes from this method. + The @c isRegistered and @c hasFailedRegistration flags reflect the results of this registration - attempt. Returns the value of isRegistered. + attempt. Returns true if the font is registered. If font registration fails, subsequent calls to + registerFont will fail unless unregisterFont is called first. */ - (BOOL)registerFont; +/** + Attempts to unregister the font. + + All instances of MDCFontDiskLoader with the same fontURL will reflect changes from this method. + + Returns true when the font is unregistered. Resets @c hasFailedRegistration back to false. + */ +- (BOOL)unregisterFont; + #pragma mark Accessing the font's registration status -/** The registered state of the custom font. */ -@property(nonatomic) BOOL isRegistered; +/** + The registered state of the custom font. + + All instances of MDCFontDiskLoader with the same fontURL have the same value of @c isRegistered. + */ +@property(nonatomic, readonly) BOOL isRegistered; + +/** + This flag is true when the registration failed. -/** This flag is true when the registration failed. It prevents future attempts at registration. */ -@property(nonatomic) BOOL hasFailedRegistration; + It prevents future attempts at registration. To reset call @c unregisterFont. + */ +@property(nonatomic, readonly) BOOL hasFailedRegistration; #pragma mark Requesting fonts of a given size /** A convience method for getting a font. */ - (nullable UIFont *)fontOfSize:(CGFloat)fontSize; +// TODO: On or after 6/8/2016 delete these deprecations +- (void)setIsRegistered:(BOOL)isRegistered __deprecated_msg("This setter is no longer public"); +- (void)setHasFailedRegistration:(BOOL)hasFailedRegistration __deprecated_msg("This setter is no longer public"); + @end diff --git a/components/FontDiskLoader/src/MDCFontDiskLoader.m b/components/FontDiskLoader/src/MDCFontDiskLoader.m index d13877ec45e..3d170a89166 100644 --- a/components/FontDiskLoader/src/MDCFontDiskLoader.m +++ b/components/FontDiskLoader/src/MDCFontDiskLoader.m @@ -20,8 +20,12 @@ @interface MDCFontDiskLoader () @property(nonatomic, strong) NSURL *fontURL; +@property(nonatomic) BOOL isRegistered; +@property(nonatomic) BOOL hasFailedRegistration; @end +static NSMutableSet *registeredFonts; + @implementation MDCFontDiskLoader - (instancetype)initWithName:(NSString *)fontName URL:(NSURL *)fontURL { @@ -49,7 +53,7 @@ - (instancetype)initWithFontName:(NSString *)fontName } - (BOOL)registerFont { - if (_isRegistered) { + if (self.isRegistered) { return YES; } if (_hasFailedRegistration) { @@ -61,16 +65,23 @@ - (BOOL)registerFont { return NO; } CFErrorRef error = NULL; - _isRegistered = CTFontManagerRegisterFontsForURL((__bridge CFURLRef)self.fontURL, - kCTFontManagerScopeProcess, - &error); - if (!_isRegistered) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + self.isRegistered = CTFontManagerRegisterFontsForURL((__bridge CFURLRef)self.fontURL, + kCTFontManagerScopeProcess, + &error); +#pragma clang diagnostic pop + + if (!self.isRegistered) { if (error && CFErrorGetCode(error) == kCTFontManagerErrorAlreadyRegistered) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // If it's already been loaded by somebody else, we don't care. // We do not check the error domain to make sure they match because // kCTFontManagerErrorDomain is not defined in the iOS 8 SDK. // Radar 18651170 iOS 8 SDK missing definition for kCTFontManagerErrorDomain - _isRegistered = YES; + self.isRegistered = YES; +#pragma clang diagnostic pop } else { NSLog(@"Failed to load font: %@", error); _hasFailedRegistration = YES; @@ -79,12 +90,38 @@ - (BOOL)registerFont { if (error) { CFRelease(error); } - return _isRegistered; + return self.isRegistered; +} + +- (BOOL)unregisterFont { + if (!self.isRegistered) { + _hasFailedRegistration = NO; + return YES; + } + CFErrorRef error = NULL; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + self.isRegistered = !CTFontManagerUnregisterFontsForURL((__bridge CFURLRef)self.fontURL, + kCTFontManagerScopeProcess, + &error); +#pragma clang diagnostic pop + + if (self.isRegistered || error) { + NSLog(@"Failed to unregister font: %@", error); + } + return !self.isRegistered; } - (UIFont *)fontOfSize:(CGFloat)fontSize { [self registerFont]; - return [UIFont fontWithName:self.fontName size:fontSize]; + UIFont *font = [UIFont fontWithName:self.fontName size:fontSize]; +#if DEBUG + if (font == nil) { + NSLog(@"Warning: This log will turn into an NSAssert on or after 6/8/2016"); + NSLog(@"Failed to find font: %@ in file at %@", self.fontName, self.fontURL); + } +#endif + return font; } - (NSString *)description { @@ -112,4 +149,34 @@ - (NSUInteger)hash { return self.fontName.hash ^ self.fontURL.hash; } +- (id)copyWithZone:(NSZone *)zone { + return self; +} + +- (BOOL)isRegistered { + @synchronized(registeredFonts) { + return [registeredFonts containsObject:self.fontURL]; + } +} + +- (void)setIsRegistered:(BOOL)isRegistered { + @synchronized(registeredFonts) { + if (isRegistered == [registeredFonts containsObject:self.fontURL]) { + return; // Already in the correct state; + } + if (isRegistered) { + [registeredFonts addObject:self.fontURL]; + } else { + [registeredFonts removeObject:self.fontURL]; + } + } +} + ++ (void)load { + static dispatch_once_t once; + dispatch_once(&once, ^{ + registeredFonts = [[NSMutableSet alloc] init]; + }); +} + @end diff --git a/components/FontDiskLoader/tests/unit/FontDiskLoaderTests.m b/components/FontDiskLoader/tests/unit/FontDiskLoaderTests.m index 0b2198f9d8c..51f5626c946 100644 --- a/components/FontDiskLoader/tests/unit/FontDiskLoaderTests.m +++ b/components/FontDiskLoader/tests/unit/FontDiskLoaderTests.m @@ -43,7 +43,7 @@ - (MDCFontDiskLoader *)validResource { - (MDCFontDiskLoader *)invalidResource { NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(MDCRobotoFontLoaderClassname)]; - return [[MDCFontDiskLoader alloc] initWithFontName:MDCRobotoRegularFontName + return [[MDCFontDiskLoader alloc] initWithFontName:@"some invalid font name" filename:@"some invalid filename" bundleFileName:MDCRobotoBundle baseBundle:bundle]; @@ -74,6 +74,44 @@ - (void)testRegisterFont { XCTAssertTrue(resource.isRegistered); } +- (void)testUnregisterFont { + // Given + MDCFontDiskLoader *resource = [self validResource]; + [resource registerFont]; + + // When + BOOL success = [resource unregisterFont]; + + // Then + XCTAssertFalse(resource.isRegistered); + XCTAssertTrue(success); +} + +- (void)testUnregisterFailedRegistration { + // Given + MDCFontDiskLoader *resource = [self invalidResource]; + [resource registerFont]; + + // When + [resource unregisterFont]; + + // Then + XCTAssertFalse(resource.isRegistered); + XCTAssertFalse(resource.hasFailedRegistration); +} + +- (void)testUnregisterNotRegistered { + // Given + MDCFontDiskLoader *resource = [self invalidResource]; + + // When + [resource unregisterFont]; + + // Then + XCTAssertFalse(resource.isRegistered); + XCTAssertFalse(resource.hasFailedRegistration); +} + - (void)testRegisterFontFailure { // Given MDCFontDiskLoader *resource = [self invalidResource]; @@ -82,9 +120,35 @@ - (void)testRegisterFontFailure { [resource registerFont]; // Then + XCTAssertNil([resource fontOfSize:10]); XCTAssertTrue(resource.hasFailedRegistration); } +- (void)testCopy { + // Given + MDCFontDiskLoader *loader = [self validResource]; + + // When + MDCFontDiskLoader *secondFontLoader = [loader copy]; + + // Then + XCTAssertEqualObjects(loader, secondFontLoader); +} + +- (void)testIsRegisteredOfSecondFontLoader { + // Given + MDCFontDiskLoader *loader = [self validResource]; + MDCFontDiskLoader *secondFontLoader = + [[MDCFontDiskLoader alloc] initWithName:loader.fontName + URL:loader.fontURL]; + + // When + [loader registerFont]; + + // Then + XCTAssertEqual(loader.isRegistered, secondFontLoader.isRegistered); +} + - (void)testProvidesACustomFont { // Given MDCFontDiskLoader *resource = [self validResource]; @@ -195,4 +259,5 @@ - (void)testEquals { XCTAssertEqualObjects(loader, secondLoader); XCTAssertEqual([loader hash], [secondLoader hash]); } + @end diff --git a/components/PageControl/examples/PageControlTypicalUseExample.swift b/components/PageControl/examples/PageControlTypicalUseExample.swift index 1a20da3b503..0d4dbd6267b 100644 --- a/components/PageControl/examples/PageControlTypicalUseExample.swift +++ b/components/PageControl/examples/PageControlTypicalUseExample.swift @@ -63,7 +63,7 @@ class PageControlSwiftExampleViewController: UIViewController, UIScrollViewDeleg let pageControlSize = pageControl.sizeThatFits(view.bounds.size) pageControl.frame = CGRectMake(0, view.bounds.height - pageControlSize.height, view.bounds.width, pageControlSize.height); - pageControl.addTarget(self, action: "didChangePage:", forControlEvents: .ValueChanged) + pageControl.addTarget(self, action: #selector(didChangePage), forControlEvents: .ValueChanged) pageControl.autoresizingMask = [.FlexibleTopMargin, .FlexibleWidth]; view.addSubview(pageControl) } diff --git a/components/RobotoFontLoader/README.md b/components/RobotoFontLoader/README.md index 993242c719f..2ab3b32d4ce 100644 --- a/components/RobotoFontLoader/README.md +++ b/components/RobotoFontLoader/README.md @@ -18,11 +18,9 @@ The Roboto Font Loader lazy loads the Roboto font. diff --git a/components/ShadowLayer/examples/ShadowDragSquareExampleViewController.swift b/components/ShadowLayer/examples/ShadowDragSquareExampleViewController.swift index 6461d2a42b8..fda804d2679 100644 --- a/components/ShadowLayer/examples/ShadowDragSquareExampleViewController.swift +++ b/components/ShadowLayer/examples/ShadowDragSquareExampleViewController.swift @@ -43,7 +43,7 @@ class ShadowDragSquareExampleViewController: UIViewController { self.blueView.setElevation(kRestingCardElevation) - longPressRecogniser.addTarget(self, action: "longPressedInView:") + longPressRecogniser.addTarget(self, action: #selector(longPressedInView)) longPressRecogniser.minimumPressDuration = 0.0 self.blueView.addGestureRecognizer(longPressRecogniser) } diff --git a/components/Switch/examples/SwitchSwiftExampleViewController.swift b/components/Switch/examples/SwitchSwiftExampleViewController.swift index e3b8fc8f258..bc53165a39e 100644 --- a/components/Switch/examples/SwitchSwiftExampleViewController.swift +++ b/components/Switch/examples/SwitchSwiftExampleViewController.swift @@ -27,7 +27,7 @@ class SwitchSwiftExampleViewController : UIViewController { view.backgroundColor = UIColor.whiteColor() switchComponent.on = true - switchComponent.addTarget(self, action: Selector("didChangeSwitchValue:"), forControlEvents: UIControlEvents.ValueChanged) + switchComponent.addTarget(self, action: #selector(didChangeSwitchValue), forControlEvents: UIControlEvents.ValueChanged) view.addSubview(switchComponent) switchComponent.center = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); switchComponent.autoresizingMask = [.FlexibleBottomMargin, .FlexibleTopMargin, .FlexibleLeftMargin, .FlexibleRightMargin] diff --git a/components/private/ThumbTrack/src/MDCThumbTrack.m b/components/private/ThumbTrack/src/MDCThumbTrack.m index dbf5932a993..8ddbb7a2d33 100644 --- a/components/private/ThumbTrack/src/MDCThumbTrack.m +++ b/components/private/ThumbTrack/src/MDCThumbTrack.m @@ -437,7 +437,11 @@ - (void)updateColorsAnimated:(BOOL)animated withDuration:(NSTimeInterval)duratio _trackOnLayer.backgroundColor = _trackOnColor.CGColor; CGFloat anchor = [self thumbPositionForValue:_filledTrackAnchorValue].x; - if (!_trackEndsAreInset) { + + if (_trackEndsAreInset) { + // Account for the fact that _trackView is actually shorter in this case + anchor -= _thumbRadius; + } else { if (_filledTrackAnchorValue <= _minimumValue) { anchor -= _thumbRadius; } @@ -470,17 +474,21 @@ - (void)updateViewsAnimated:(BOOL)animated withDuration:(NSTimeInterval)duration // Move thumb position. CGPoint point = [self thumbPositionForValue:_value]; _thumbView.center = point; - _trackView.frame = - CGRectMake(0, self.center.y - (_trackHeight / 2), CGRectGetWidth(self.bounds), _trackHeight); + if (_trackEndsAreInset) { + _trackView.frame = + CGRectMake(_thumbView.cornerRadius, self.center.y - (_trackHeight / 2), + CGRectGetWidth(self.bounds) - (_thumbView.cornerRadius * 2), _trackHeight); + } else { + _trackView.frame = + CGRectMake(0, self.center.y - (_trackHeight / 2), CGRectGetWidth(self.bounds), _trackHeight); + } + [self updateTrackMask]; [self updateColorsAnimated:animated withDuration:duration]; } - (void)updateTrackMask { CGRect maskFrame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), _trackHeight); - if (_trackEndsAreInset) { - maskFrame = CGRectInset(maskFrame, _thumbView.cornerRadius, 0); - } CGMutablePathRef path = CGPathCreateMutable(); CGFloat cornerRadius = _trackHeight / 2; diff --git a/demos/Pesto/Pesto/Info.plist b/demos/Pesto/Pesto/Info.plist index 862232fff95..6ad3a891b19 100644 --- a/demos/Pesto/Pesto/Info.plist +++ b/demos/Pesto/Pesto/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) + com.google.mdc-pesto CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/demos/Pesto/Podfile.lock b/demos/Pesto/Podfile.lock index 935a8ca6b9c..ec43419cc15 100644 --- a/demos/Pesto/Podfile.lock +++ b/demos/Pesto/Podfile.lock @@ -1,27 +1,29 @@ PODS: - - MaterialComponents (10.0.0): - - MaterialComponents/AppBar (= 10.0.0) - - MaterialComponents/ButtonBar (= 10.0.0) - - MaterialComponents/Buttons (= 10.0.0) - - MaterialComponents/CollectionCells (= 10.0.0) - - MaterialComponents/CollectionLayoutAttributes (= 10.0.0) - - MaterialComponents/Collections (= 10.0.0) - - MaterialComponents/FlexibleHeader (= 10.0.0) - - MaterialComponents/FontDiskLoader (= 10.0.0) - - MaterialComponents/HeaderStackView (= 10.0.0) - - MaterialComponents/Ink (= 10.0.0) - - MaterialComponents/NavigationBar (= 10.0.0) - - MaterialComponents/PageControl (= 10.0.0) - - MaterialComponents/Palettes (= 10.0.0) - - MaterialComponents/private (= 10.0.0) - - MaterialComponents/RobotoFontLoader (= 10.0.0) - - MaterialComponents/ShadowElevations (= 10.0.0) - - MaterialComponents/ShadowLayer (= 10.0.0) - - MaterialComponents/Slider (= 10.0.0) - - MaterialComponents/SpritedAnimationView (= 10.0.0) - - MaterialComponents/Switch (= 10.0.0) - - MaterialComponents/Typography (= 10.0.0) - - MaterialComponents/AppBar (10.0.0): + - MaterialComponents (10.1.0): + - MaterialComponents/ActivityIndicator (= 10.1.0) + - MaterialComponents/AppBar (= 10.1.0) + - MaterialComponents/ButtonBar (= 10.1.0) + - MaterialComponents/Buttons (= 10.1.0) + - MaterialComponents/CollectionCells (= 10.1.0) + - MaterialComponents/CollectionLayoutAttributes (= 10.1.0) + - MaterialComponents/Collections (= 10.1.0) + - MaterialComponents/FlexibleHeader (= 10.1.0) + - MaterialComponents/FontDiskLoader (= 10.1.0) + - MaterialComponents/HeaderStackView (= 10.1.0) + - MaterialComponents/Ink (= 10.1.0) + - MaterialComponents/NavigationBar (= 10.1.0) + - MaterialComponents/PageControl (= 10.1.0) + - MaterialComponents/Palettes (= 10.1.0) + - MaterialComponents/private (= 10.1.0) + - MaterialComponents/RobotoFontLoader (= 10.1.0) + - MaterialComponents/ShadowElevations (= 10.1.0) + - MaterialComponents/ShadowLayer (= 10.1.0) + - MaterialComponents/Slider (= 10.1.0) + - MaterialComponents/SpritedAnimationView (= 10.1.0) + - MaterialComponents/Switch (= 10.1.0) + - MaterialComponents/Typography (= 10.1.0) + - MaterialComponents/ActivityIndicator (10.1.0) + - MaterialComponents/AppBar (10.1.0): - MaterialComponents/FlexibleHeader - MaterialComponents/HeaderStackView - MaterialComponents/NavigationBar @@ -29,14 +31,14 @@ PODS: - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/ButtonBar (10.0.0): + - MaterialComponents/ButtonBar (10.1.0): - MaterialComponents/Buttons - - MaterialComponents/Buttons (10.0.0): + - MaterialComponents/Buttons (10.1.0): - MaterialComponents/Ink - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/CollectionCells (10.0.0): + - MaterialComponents/CollectionCells (10.1.0): - MaterialComponents/CollectionLayoutAttributes - MaterialComponents/Ink - MaterialComponents/private/Icons/ic_check @@ -46,68 +48,68 @@ PODS: - MaterialComponents/private/Icons/ic_radio_button_unchecked - MaterialComponents/private/Icons/ic_reorder - MaterialComponents/Typography - - MaterialComponents/CollectionLayoutAttributes (10.0.0) - - MaterialComponents/Collections (10.0.0): + - MaterialComponents/CollectionLayoutAttributes (10.1.0) + - MaterialComponents/Collections (10.1.0): - MaterialComponents/CollectionCells - MaterialComponents/CollectionLayoutAttributes - MaterialComponents/Ink - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/FlexibleHeader (10.0.0) - - MaterialComponents/FontDiskLoader (10.0.0) - - MaterialComponents/HeaderStackView (10.0.0) - - MaterialComponents/Ink (10.0.0) - - MaterialComponents/NavigationBar (10.0.0): + - MaterialComponents/FlexibleHeader (10.1.0) + - MaterialComponents/FontDiskLoader (10.1.0) + - MaterialComponents/HeaderStackView (10.1.0) + - MaterialComponents/Ink (10.1.0) + - MaterialComponents/NavigationBar (10.1.0): - MaterialComponents/ButtonBar - MaterialComponents/Typography - - MaterialComponents/PageControl (10.0.0) - - MaterialComponents/Palettes (10.0.0) - - MaterialComponents/private (10.0.0): - - MaterialComponents/private/Color (= 10.0.0) - - MaterialComponents/private/Icons (= 10.0.0) - - MaterialComponents/private/ThumbTrack (= 10.0.0) - - MaterialComponents/private/Color (10.0.0) - - MaterialComponents/private/Icons (10.0.0): - - MaterialComponents/private/Icons/Base (= 10.0.0) - - MaterialComponents/private/Icons/ic_arrow_back (= 10.0.0) - - MaterialComponents/private/Icons/ic_check (= 10.0.0) - - MaterialComponents/private/Icons/ic_check_circle (= 10.0.0) - - MaterialComponents/private/Icons/ic_chevron_right (= 10.0.0) - - MaterialComponents/private/Icons/ic_info (= 10.0.0) - - MaterialComponents/private/Icons/ic_radio_button_unchecked (= 10.0.0) - - MaterialComponents/private/Icons/ic_reorder (= 10.0.0) - - MaterialComponents/private/Icons/Base (10.0.0) - - MaterialComponents/private/Icons/ic_arrow_back (10.0.0): + - MaterialComponents/PageControl (10.1.0) + - MaterialComponents/Palettes (10.1.0) + - MaterialComponents/private (10.1.0): + - MaterialComponents/private/Color (= 10.1.0) + - MaterialComponents/private/Icons (= 10.1.0) + - MaterialComponents/private/ThumbTrack (= 10.1.0) + - MaterialComponents/private/Color (10.1.0) + - MaterialComponents/private/Icons (10.1.0): + - MaterialComponents/private/Icons/Base (= 10.1.0) + - MaterialComponents/private/Icons/ic_arrow_back (= 10.1.0) + - MaterialComponents/private/Icons/ic_check (= 10.1.0) + - MaterialComponents/private/Icons/ic_check_circle (= 10.1.0) + - MaterialComponents/private/Icons/ic_chevron_right (= 10.1.0) + - MaterialComponents/private/Icons/ic_info (= 10.1.0) + - MaterialComponents/private/Icons/ic_radio_button_unchecked (= 10.1.0) + - MaterialComponents/private/Icons/ic_reorder (= 10.1.0) + - MaterialComponents/private/Icons/Base (10.1.0) + - MaterialComponents/private/Icons/ic_arrow_back (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_check (10.0.0): + - MaterialComponents/private/Icons/ic_check (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_check_circle (10.0.0): + - MaterialComponents/private/Icons/ic_check_circle (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_chevron_right (10.0.0): + - MaterialComponents/private/Icons/ic_chevron_right (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_info (10.0.0): + - MaterialComponents/private/Icons/ic_info (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_radio_button_unchecked (10.0.0): + - MaterialComponents/private/Icons/ic_radio_button_unchecked (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_reorder (10.0.0): + - MaterialComponents/private/Icons/ic_reorder (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/ThumbTrack (10.0.0): + - MaterialComponents/private/ThumbTrack (10.1.0): - MaterialComponents/Ink - MaterialComponents/private/Color - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - - MaterialComponents/RobotoFontLoader (10.0.0): + - MaterialComponents/RobotoFontLoader (10.1.0): - MaterialComponents/FontDiskLoader - MaterialComponents/Typography - - MaterialComponents/ShadowElevations (10.0.0) - - MaterialComponents/ShadowLayer (10.0.0) - - MaterialComponents/Slider (10.0.0): + - MaterialComponents/ShadowElevations (10.1.0) + - MaterialComponents/ShadowLayer (10.1.0) + - MaterialComponents/Slider (10.1.0): - MaterialComponents/private/ThumbTrack - - MaterialComponents/SpritedAnimationView (10.0.0) - - MaterialComponents/Switch (10.0.0): + - MaterialComponents/SpritedAnimationView (10.1.0) + - MaterialComponents/Switch (10.1.0): - MaterialComponents/private/ThumbTrack - - MaterialComponents/Typography (10.0.0) + - MaterialComponents/Typography (10.1.0) DEPENDENCIES: - MaterialComponents (from `../../`) @@ -117,7 +119,7 @@ EXTERNAL SOURCES: :path: ../../ SPEC CHECKSUMS: - MaterialComponents: 1ba34edf996dbdf6acaea8b3051b5d78ab9d252f + MaterialComponents: 65ac94f1904a9ddd867b95c2f3c55222943fd4fa PODFILE CHECKSUM: f138be16d4835113ff672258fc7529fad3f90e91 diff --git a/demos/Shrine/Podfile.lock b/demos/Shrine/Podfile.lock index 93b8f4ed911..82b32990803 100644 --- a/demos/Shrine/Podfile.lock +++ b/demos/Shrine/Podfile.lock @@ -1,27 +1,29 @@ PODS: - - MaterialComponents (10.0.0): - - MaterialComponents/AppBar (= 10.0.0) - - MaterialComponents/ButtonBar (= 10.0.0) - - MaterialComponents/Buttons (= 10.0.0) - - MaterialComponents/CollectionCells (= 10.0.0) - - MaterialComponents/CollectionLayoutAttributes (= 10.0.0) - - MaterialComponents/Collections (= 10.0.0) - - MaterialComponents/FlexibleHeader (= 10.0.0) - - MaterialComponents/FontDiskLoader (= 10.0.0) - - MaterialComponents/HeaderStackView (= 10.0.0) - - MaterialComponents/Ink (= 10.0.0) - - MaterialComponents/NavigationBar (= 10.0.0) - - MaterialComponents/PageControl (= 10.0.0) - - MaterialComponents/Palettes (= 10.0.0) - - MaterialComponents/private (= 10.0.0) - - MaterialComponents/RobotoFontLoader (= 10.0.0) - - MaterialComponents/ShadowElevations (= 10.0.0) - - MaterialComponents/ShadowLayer (= 10.0.0) - - MaterialComponents/Slider (= 10.0.0) - - MaterialComponents/SpritedAnimationView (= 10.0.0) - - MaterialComponents/Switch (= 10.0.0) - - MaterialComponents/Typography (= 10.0.0) - - MaterialComponents/AppBar (10.0.0): + - MaterialComponents (10.1.0): + - MaterialComponents/ActivityIndicator (= 10.1.0) + - MaterialComponents/AppBar (= 10.1.0) + - MaterialComponents/ButtonBar (= 10.1.0) + - MaterialComponents/Buttons (= 10.1.0) + - MaterialComponents/CollectionCells (= 10.1.0) + - MaterialComponents/CollectionLayoutAttributes (= 10.1.0) + - MaterialComponents/Collections (= 10.1.0) + - MaterialComponents/FlexibleHeader (= 10.1.0) + - MaterialComponents/FontDiskLoader (= 10.1.0) + - MaterialComponents/HeaderStackView (= 10.1.0) + - MaterialComponents/Ink (= 10.1.0) + - MaterialComponents/NavigationBar (= 10.1.0) + - MaterialComponents/PageControl (= 10.1.0) + - MaterialComponents/Palettes (= 10.1.0) + - MaterialComponents/private (= 10.1.0) + - MaterialComponents/RobotoFontLoader (= 10.1.0) + - MaterialComponents/ShadowElevations (= 10.1.0) + - MaterialComponents/ShadowLayer (= 10.1.0) + - MaterialComponents/Slider (= 10.1.0) + - MaterialComponents/SpritedAnimationView (= 10.1.0) + - MaterialComponents/Switch (= 10.1.0) + - MaterialComponents/Typography (= 10.1.0) + - MaterialComponents/ActivityIndicator (10.1.0) + - MaterialComponents/AppBar (10.1.0): - MaterialComponents/FlexibleHeader - MaterialComponents/HeaderStackView - MaterialComponents/NavigationBar @@ -29,14 +31,14 @@ PODS: - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/ButtonBar (10.0.0): + - MaterialComponents/ButtonBar (10.1.0): - MaterialComponents/Buttons - - MaterialComponents/Buttons (10.0.0): + - MaterialComponents/Buttons (10.1.0): - MaterialComponents/Ink - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/CollectionCells (10.0.0): + - MaterialComponents/CollectionCells (10.1.0): - MaterialComponents/CollectionLayoutAttributes - MaterialComponents/Ink - MaterialComponents/private/Icons/ic_check @@ -46,68 +48,68 @@ PODS: - MaterialComponents/private/Icons/ic_radio_button_unchecked - MaterialComponents/private/Icons/ic_reorder - MaterialComponents/Typography - - MaterialComponents/CollectionLayoutAttributes (10.0.0) - - MaterialComponents/Collections (10.0.0): + - MaterialComponents/CollectionLayoutAttributes (10.1.0) + - MaterialComponents/Collections (10.1.0): - MaterialComponents/CollectionCells - MaterialComponents/CollectionLayoutAttributes - MaterialComponents/Ink - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - MaterialComponents/Typography - - MaterialComponents/FlexibleHeader (10.0.0) - - MaterialComponents/FontDiskLoader (10.0.0) - - MaterialComponents/HeaderStackView (10.0.0) - - MaterialComponents/Ink (10.0.0) - - MaterialComponents/NavigationBar (10.0.0): + - MaterialComponents/FlexibleHeader (10.1.0) + - MaterialComponents/FontDiskLoader (10.1.0) + - MaterialComponents/HeaderStackView (10.1.0) + - MaterialComponents/Ink (10.1.0) + - MaterialComponents/NavigationBar (10.1.0): - MaterialComponents/ButtonBar - MaterialComponents/Typography - - MaterialComponents/PageControl (10.0.0) - - MaterialComponents/Palettes (10.0.0) - - MaterialComponents/private (10.0.0): - - MaterialComponents/private/Color (= 10.0.0) - - MaterialComponents/private/Icons (= 10.0.0) - - MaterialComponents/private/ThumbTrack (= 10.0.0) - - MaterialComponents/private/Color (10.0.0) - - MaterialComponents/private/Icons (10.0.0): - - MaterialComponents/private/Icons/Base (= 10.0.0) - - MaterialComponents/private/Icons/ic_arrow_back (= 10.0.0) - - MaterialComponents/private/Icons/ic_check (= 10.0.0) - - MaterialComponents/private/Icons/ic_check_circle (= 10.0.0) - - MaterialComponents/private/Icons/ic_chevron_right (= 10.0.0) - - MaterialComponents/private/Icons/ic_info (= 10.0.0) - - MaterialComponents/private/Icons/ic_radio_button_unchecked (= 10.0.0) - - MaterialComponents/private/Icons/ic_reorder (= 10.0.0) - - MaterialComponents/private/Icons/Base (10.0.0) - - MaterialComponents/private/Icons/ic_arrow_back (10.0.0): + - MaterialComponents/PageControl (10.1.0) + - MaterialComponents/Palettes (10.1.0) + - MaterialComponents/private (10.1.0): + - MaterialComponents/private/Color (= 10.1.0) + - MaterialComponents/private/Icons (= 10.1.0) + - MaterialComponents/private/ThumbTrack (= 10.1.0) + - MaterialComponents/private/Color (10.1.0) + - MaterialComponents/private/Icons (10.1.0): + - MaterialComponents/private/Icons/Base (= 10.1.0) + - MaterialComponents/private/Icons/ic_arrow_back (= 10.1.0) + - MaterialComponents/private/Icons/ic_check (= 10.1.0) + - MaterialComponents/private/Icons/ic_check_circle (= 10.1.0) + - MaterialComponents/private/Icons/ic_chevron_right (= 10.1.0) + - MaterialComponents/private/Icons/ic_info (= 10.1.0) + - MaterialComponents/private/Icons/ic_radio_button_unchecked (= 10.1.0) + - MaterialComponents/private/Icons/ic_reorder (= 10.1.0) + - MaterialComponents/private/Icons/Base (10.1.0) + - MaterialComponents/private/Icons/ic_arrow_back (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_check (10.0.0): + - MaterialComponents/private/Icons/ic_check (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_check_circle (10.0.0): + - MaterialComponents/private/Icons/ic_check_circle (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_chevron_right (10.0.0): + - MaterialComponents/private/Icons/ic_chevron_right (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_info (10.0.0): + - MaterialComponents/private/Icons/ic_info (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_radio_button_unchecked (10.0.0): + - MaterialComponents/private/Icons/ic_radio_button_unchecked (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/Icons/ic_reorder (10.0.0): + - MaterialComponents/private/Icons/ic_reorder (10.1.0): - MaterialComponents/private/Icons/Base - - MaterialComponents/private/ThumbTrack (10.0.0): + - MaterialComponents/private/ThumbTrack (10.1.0): - MaterialComponents/Ink - MaterialComponents/private/Color - MaterialComponents/ShadowElevations - MaterialComponents/ShadowLayer - - MaterialComponents/RobotoFontLoader (10.0.0): + - MaterialComponents/RobotoFontLoader (10.1.0): - MaterialComponents/FontDiskLoader - MaterialComponents/Typography - - MaterialComponents/ShadowElevations (10.0.0) - - MaterialComponents/ShadowLayer (10.0.0) - - MaterialComponents/Slider (10.0.0): + - MaterialComponents/ShadowElevations (10.1.0) + - MaterialComponents/ShadowLayer (10.1.0) + - MaterialComponents/Slider (10.1.0): - MaterialComponents/private/ThumbTrack - - MaterialComponents/SpritedAnimationView (10.0.0) - - MaterialComponents/Switch (10.0.0): + - MaterialComponents/SpritedAnimationView (10.1.0) + - MaterialComponents/Switch (10.1.0): - MaterialComponents/private/ThumbTrack - - MaterialComponents/Typography (10.0.0) + - MaterialComponents/Typography (10.1.0) DEPENDENCIES: - MaterialComponents (from `../../`) @@ -117,7 +119,7 @@ EXTERNAL SOURCES: :path: ../../ SPEC CHECKSUMS: - MaterialComponents: 1ba34edf996dbdf6acaea8b3051b5d78ab9d252f + MaterialComponents: 65ac94f1904a9ddd867b95c2f3c55222943fd4fa PODFILE CHECKSUM: b585ca32a2884e050823cc1f861e8b7246f7dcc1 diff --git a/demos/Shrine/Shrine/Info.plist b/demos/Shrine/Shrine/Info.plist index e9241ee9d4f..f007b22f716 100644 --- a/demos/Shrine/Shrine/Info.plist +++ b/demos/Shrine/Shrine/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) + com.google.mdc-shrine CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/demos/Shrine/Shrine/ShrineDetailViewController.swift b/demos/Shrine/Shrine/ShrineDetailViewController.swift index 11a63462da5..dec14b28627 100644 --- a/demos/Shrine/Shrine/ShrineDetailViewController.swift +++ b/demos/Shrine/Shrine/ShrineDetailViewController.swift @@ -114,7 +114,7 @@ class ShrineDetailViewController: UIViewController { dismissBtn.customTitleColor = UIColor.grayColor() dismissBtn.sizeToFit() dismissBtn.frame = CGRectMake(8, 28, dismissBtn.frame.width, dismissBtn.frame.height) - dismissBtn.addTarget(self, action: "dismissDetails", + dismissBtn.addTarget(self, action: #selector(dismissDetails), forControlEvents: .TouchUpInside) self.view.addSubview(dismissBtn) } diff --git a/demos/Shrine/Shrine/ShrineHeaderContentView.swift b/demos/Shrine/Shrine/ShrineHeaderContentView.swift index 2391994bbe1..4a1386a6458 100644 --- a/demos/Shrine/Shrine/ShrineHeaderContentView.swift +++ b/demos/Shrine/Shrine/ShrineHeaderContentView.swift @@ -74,7 +74,7 @@ class ShrineHeaderContentView: UIView, UIScrollViewDelegate { boundsHeight - pageControlSize.height, boundsWidth, pageControlSize.height) - pageControl.addTarget(self, action: "didChangePage:", + pageControl.addTarget(self, action: #selector(didChangePage), forControlEvents: UIControlEvents.ValueChanged) self.addSubview(pageControl) diff --git a/site-index.md b/site-index.md index 27ecc16551f..716a68cbcd7 100644 --- a/site-index.md +++ b/site-index.md @@ -13,6 +13,7 @@ An easy way to create beautiful apps with modular and customizable UI compo [Get Started](#quickstart) +[View on GitHub](https://github.com/google/material-components-ios) @@ -139,5 +140,8 @@ An easy way to create beautiful apps with modular and customizable UI compo - [Explore our Code Samples]({{ site.folder }}/howto/tutorial/#sample-code) + + - [View the project on Github](https://github.com/google/material-components-ios/) +