Merge branch 'release-candidate' into stable
diff --git a/CHANGELOG.md b/CHANGELOG.md index 440c57b..8a2ab40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -1,3 +1,93 @@ +# 124.2.0 + +In this minor release, we added opt-in feature from MDCShadowLayer to MDCShadow for several components, annotated APIs with tvOS availability, and fixed a variety of bugs on components. + +## New features + +### BottomSheet +`MDCBottomSheetController` has a new `ignoreKeyboardHeight` property to control BottomSheet's behavior when keyboard is present. + +### Chips +`MDCChipFieldDelegate` has a new delegate method `chipFieldShouldEndEditing` to match `chipFieldShouldBeginEditing`. + +## Component changes + +### ActionSheet + +* [Allow clients to get the view associated with a given action.](https://github.com/material-components/material-components-ios/commit/1524182f7c54917d0c1c0b53a3f906aca00b7827) (Cody Weaver) +* [Inform the delegate that the action sheet is dismissed when the dismissal is issued from the accessibility gesture.](https://github.com/material-components/material-components-ios/commit/1405e1942927b964814327f872274e99ec367c44) (Nobody) + +### ActivityIndicator + +* [Internal change.](https://github.com/material-components/material-components-ios/commit/5cb61f3efe1555abce020f2764a4870fdca0a8fd) (Nobody) + +### BottomNavigation + +* [Adds opt-in from MDCShadowLayer to MDCShadow.](https://github.com/material-components/material-components-ios/commit/e5a68ba77edb55af83f76ddb9071334b6d6d672c) (Yarden Eitan) +* [Only initialize blur effect view if it is not hidden.](https://github.com/material-components/material-components-ios/commit/0f99d29856ff36a30e787e765c09047d7eba7330) (Alyssa Weiss) + +### BottomSheet + +* [Add ignoreKeyboardHeight to allow configuring bottomSheet's behavior when keyboard is present.](https://github.com/material-components/material-components-ios/commit/dfe9dcb58ef177a13cb6b1f28f47c88eeba401cd) (Wenyu Zhang) +* [Adjust content view frame when safe area insets change.](https://github.com/material-components/material-components-ios/commit/ac810a4f3891f364e3f34c6448e728c5449d3300) (Alyssa Weiss) +* [Fix Bottom sheet bug that was causing flickering.](https://github.com/material-components/material-components-ios/commit/14a603f05a4c1d368559ea4fdb34ff90112c4946) (Alyssa Weiss) + +### ButtonBar + +* [Fix use of wrong enum values (using FloatingBar rather than ButtonBar)](https://github.com/material-components/material-components-ios/commit/40453fe9d2b9363044a72cf09b0109cb6e4bf7b6) (Yarden Eitan) + +### Buttons + +* [Attempt to reduce flakiness of the buttons screenshot tests.](https://github.com/material-components/material-components-ios/commit/8465222386b80bbd39953785edb3a99f1a7b16bc) (Jeff Verkoeyen) + +### Cards + +* [Fix broken examples](https://github.com/material-components/material-components-ios/commit/381db186fe25441d41700f573dada81a0652096d) (Yarden Eitan) + +### Chips + +* [Extract clear button from MDCChipField](https://github.com/material-components/material-components-ios/commit/5cd7b82f1b003fac18950278a6db3ca777b4762e) (Andrew Overton) +* [This CL makes two changes: 1. Adds a new delegate method `chipFieldShouldEndEditing` to match `chipFieldShouldBeginEditing` 2. Moved the call to the chip field delegate for `chipFieldDidBeginEditing` and `chipFieldDidEndEditing` so they are fired at the correct time.](https://github.com/material-components/material-components-ios/commit/32fdb16b23fdb52866cab2230563c87aa84ef875) (Nobody) + +### Dialogs + +* [Avoid cutting off the top of Thai characters with diacritics. In iOS platform, text font are not strictly required to fit within the UIFont.lineHeight. Some Thai characters with diacritics are rendered outside the UILabel/UITextView's bounds.](https://github.com/material-components/material-components-ios/commit/08d42c18d8ae1991e25c97ebf456c0acb4fa292a) (Nobody) +* [Groups MDCAlertController view's accessibility children.](https://github.com/material-components/material-components-ios/commit/386923b4240dc480bc84c2f4011aa55d99b25897) (Nobody) +* [Inform the dialogPresentationControllerDelegate that the alert controller is dismissed when the dismissal is issued from the accessibility gesture.](https://github.com/material-components/material-components-ios/commit/caaed1b045775d441d6cbf9e6ad00881885a6929) (Nobody) + +### NavigationBar + +* [Upgrade Swift to 5.](https://github.com/material-components/material-components-ios/commit/4bd9eccdf130c8cac481684748f8d444fe4761a1) (Jeff Verkoeyen) + +### Shadow + +* [Add initial readme file with simple usage guide.](https://github.com/material-components/material-components-ios/commit/242f895f053ae7fea62fc02289bc99aa0ef630a2) (Yarden Eitan) +* [Code improvements for the new Shadow component.](https://github.com/material-components/material-components-ios/commit/e2f4fd39ee036bef0411b59b35080642b4a23483) (Yarden Eitan) +* [Dragon Catalog example of new in-development Shadow component.](https://github.com/material-components/material-components-ios/commit/70482cc12c44174f92f0574bb66e8df114e43dc6) (Ben Hamilton) +* [Move MDCShadowForElevation to become an instance method of MDCShadowsCollection.](https://github.com/material-components/material-components-ios/commit/ff5df61330ec171a8edbdce5a0671cffa18ea1f0) (Yarden Eitan) +* [Remove __attribute__((fallthrough))](https://github.com/material-components/material-components-ios/commit/d5db0659054f17b87e696af8eb6a7701b8c9ba08) (Yarden Eitan) + +### Typography + +* [Deleted scaledValueForValue API from Material Typography.](https://github.com/material-components/material-components-ios/commit/e12e0a457383df14b73f2fc41ca90c7075fe3097) (Alyssa Weiss) +* [Remove description related to iOS 9 as there is no longer iOS 9 support](https://github.com/material-components/material-components-ios/commit/53e1d5e945558e38310adb46def813e81ee872e3) (Alyssa Weiss) + +## Multi-component changes + +* [Add opt-in new performant shadow support.](https://github.com/material-components/material-components-ios/commit/c9904413f7b4bfcc8b8a2949b8b4809cd2a1c3b5) (Yarden Eitan) +* [Annotate APIs with tvOS availability.](https://github.com/material-components/material-components-ios/commit/9638b0bfa4c41cd66ff7675070d94d6f52cb2f0e) (Jeff Verkoeyen) +* [Disable label animation when label is truncated](https://github.com/material-components/material-components-ios/commit/2a31a3162fc31d95a4a575b6d1cbc96770cfa834) (Andrew Overton) +* [Fix broken images in iOS/Supporting APIs dev docs](https://github.com/material-components/material-components-ios/commit/39911e5e756fc2a7e186a9ad569396587d1c2845) (Nobody) +* [Fix build errors related to the Shadow component.](https://github.com/material-components/material-components-ios/commit/bf652865ce9c4ec36498f5a38b5c948974062ecc) (Jeff Verkoeyen) +* [Flattening all unit tests into single directories as per convention.](https://github.com/material-components/material-components-ios/commit/a8e4831fd0b9ea2427d392311defb707fdaa0217) (Jeff Verkoeyen) +* [Internal Change](https://github.com/material-components/material-components-ios/commit/84b83bdb8bf34172214876305a9fcc9ae5436b47) (Yarden Eitan) +* [Internal change.](https://github.com/material-components/material-components-ios/commit/1c14fb5e7b0239c1ef893cf06f1b83f49232f3f4) (Jeff Verkoeyen) +* [Internal change.](https://github.com/material-components/material-components-ios/commit/9a49fd96f94c7785c500099284f3eb36c8b46740) (Jeff Verkoeyen) +* [Miscellaneous doc updates](https://github.com/material-components/material-components-ios/commit/4e245ac6dc00546eb2760fb571ee7d2e2514e532) (Andrew Overton) +* [Remove all iOS 10 availability checks from material_components_ios now that only iOS 10+ is supported.](https://github.com/material-components/material-components-ios/commit/924c49e43b406305adaa86f681bac21b1a5458e5) (Alyssa Weiss) + +--- + # 124.1.1 In this minor release we added a new Shadow Component and removed the Shrine demo.
diff --git a/MaterialComponents.podspec b/MaterialComponents.podspec index 100e8d3..d37749e 100644 --- a/MaterialComponents.podspec +++ b/MaterialComponents.podspec
@@ -2,7 +2,7 @@ Pod::Spec.new do |mdc| mdc.name = "MaterialComponents" - mdc.version = "124.1.1" + mdc.version = "124.2.0" mdc.authors = "The Material Components authors." mdc.summary = "A collection of stand-alone production-ready UI libraries focused on design details." mdc.homepage = "https://github.com/material-components/material-components-ios" @@ -170,6 +170,7 @@ ] unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*" unit_tests.dependency "MaterialComponents/AppBar+ColorThemer" + unit_tests.dependency "MaterialComponents/AppBar+Theming" unit_tests.dependency "MaterialComponents/AppBar+TypographyThemer" end end @@ -180,14 +181,6 @@ extension.source_files = "components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/*.{h,m}", "components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/private/*.{h,m}" extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}" extension.dependency "MaterialComponents/schemes/Container" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end mdc.subspec "AppBar+ColorThemer" do |extension| @@ -239,8 +232,11 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name}/tests/unit/*.m" + "components/#{component.base_name}/tests/unit/*.{h,m,swift}" ] + unit_tests.dependency "MaterialComponents/schemes/Container" + unit_tests.dependency "MaterialComponents/private/Color" + unit_tests.dependency "MaterialComponents/private/Math" end end @@ -257,15 +253,6 @@ extension.dependency "MaterialComponents/Elevation" extension.dependency "MaterialComponents/Typography" extension.dependency "MaterialComponents/schemes/Container" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}" - ] - unit_tests.dependency "MaterialComponents/schemes/Container" - unit_tests.dependency "MaterialComponents/private/Color" - unit_tests.dependency "MaterialComponents/private/Math" - end end # BottomAppBar @@ -312,6 +299,7 @@ component.dependency "MaterialComponents/Ink" component.dependency "MaterialComponents/Ripple" component.dependency "MaterialComponents/Palettes" + component.dependency "MaterialComponents/Shadow" component.dependency "MaterialComponents/ShadowElevations" component.dependency "MaterialComponents/ShadowLayer" component.dependency "MaterialComponents/Typography" @@ -364,10 +352,8 @@ extension.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" + "components/#{extension.base_name.split('+')[0]}/tests/unit/MDCBottomNavigationThemingTests.m" ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" end end @@ -428,6 +414,7 @@ component.dependency "MaterialComponents/Elevation" component.dependency "MaterialComponents/Ink" component.dependency "MaterialComponents/Ripple" + component.dependency "MaterialComponents/Shadow" component.dependency "MaterialComponents/ShadowElevations" component.dependency "MaterialComponents/ShadowLayer" component.dependency "MaterialComponents/ShapeLibrary" @@ -515,14 +502,6 @@ extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}+TypographyThemer" extension.dependency "MaterialComponents/ShadowElevations" extension.dependency "MaterialComponents/schemes/Container" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end # ButtonBar @@ -584,14 +563,6 @@ ] extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}" extension.dependency "MaterialComponents/schemes/Container" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end # Chips @@ -635,14 +606,6 @@ extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}" extension.dependency "MaterialComponents/schemes/Container" extension.dependency "MaterialComponents/Typography" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end # CollectionCells @@ -803,14 +766,6 @@ extension.dependency "MaterialComponents/ShadowElevations" extension.dependency "MaterialComponents/schemes/Container" extension.dependency "MaterialComponents/Buttons+Theming" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end mdc.subspec "Elevation" do |component| @@ -1031,14 +986,6 @@ ] extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}" extension.dependency "MaterialComponents/schemes/Container" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end # NavigationBar @@ -1246,8 +1193,7 @@ extension.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" + "components/#{extension.base_name.split('+')[0]}/tests/unit/ProgressViewMaterialThemingTests.m", ] unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" end @@ -1274,12 +1220,30 @@ end end + # Shadow + + mdc.subspec "Shadow" do |component| + component.ios.deployment_target = '10.0' + component.public_header_files = "components/#{component.base_name}/src/*.h" + component.source_files = "components/#{component.base_name}/src/*.{h,m}" + + component.dependency "MaterialComponents/Availability" + + component.test_spec 'UnitTests' do |unit_tests| + unit_tests.source_files = [ + "components/#{component.base_name}/tests/unit/*.{h,m,swift}", + "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}" + ] + unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*" + end + end + # ShadowElevations mdc.subspec "ShadowElevations" do |component| component.ios.deployment_target = '10.0' component.public_header_files = "components/#{component.base_name}/src/*.h" - component.source_files = "components/#{component.base_name}/src/*.{h,m}" + component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}" component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ @@ -1478,10 +1442,8 @@ extension.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" + "components/#{extension.base_name.split('+')[0]}/tests/unit/TabsThemingTests.m", ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" end end @@ -1499,7 +1461,9 @@ extension.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", + "components/#{extension.base_name.split('+')[0]}/tests/unit/MDCTabBarViewIndicatorViewTests.m", + "components/#{extension.base_name.split('+')[0]}/tests/unit/MDCTabBarViewItemViewTests.m", + "components/#{extension.base_name.split('+')[0]}/tests/unit/MDCTabBarViewTests.m", ] unit_tests.dependency "MaterialComponents/AppBar" unit_tests.dependency "MaterialComponents/HeaderStackView" @@ -1519,7 +1483,7 @@ extension.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/TabBarView/MDCTabBarViewThemingTests.m", + "components/#{extension.base_name.split('+')[0]}/tests/unit/MDCTabBarViewThemingTests.m", ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1577,7 +1541,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCBaseTextAreaTests.m" ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1599,7 +1563,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCBaseTextFieldTests.m" ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1621,7 +1585,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCFilledTextAreaTests.m" ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1642,7 +1606,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCFilledTextAreaThemingTests.m" ] end end @@ -1663,7 +1627,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCFilledTextFieldTests.m" ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1684,7 +1648,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCFilledTextFieldThemingTests.m" ] end end @@ -1705,7 +1669,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCOutlinedTextAreaTests.m" ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1726,7 +1690,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCOutlinedTextAreaThemingTests.m" ] unit_tests.dependency "MaterialComponents/Availability" end @@ -1748,7 +1712,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCOutlinedTextFieldTests.m" ] unit_tests.dependency "MaterialComponents/schemes/Container" end @@ -1769,7 +1733,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/#{component.base_name.split('+')[0]}/tests/unit/MDCOutlinedTextFieldThemingTests.m" ] end end @@ -1826,14 +1790,6 @@ extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}" extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}+ColorThemer" extension.dependency "MaterialComponents/schemes/Container" - - extension.test_spec 'UnitTests' do |unit_tests| - unit_tests.source_files = [ - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}", - "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}" - ] - unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*" - end end # Themes @@ -2100,7 +2056,7 @@ component.test_spec 'UnitTests' do |unit_tests| unit_tests.source_files = [ - "components/private/#{component.base_name.split('+')[0]}/tests/unit/#{component.base_name.split('+')[1]}/*.{h,m,swift}" + "components/private/#{component.base_name.split('+')[0]}/tests/unit/*.{h,m,swift}" ] unit_tests.dependency "MaterialComponents/schemes/Container" end
diff --git a/MaterialComponentsEarlGreyTests.podspec b/MaterialComponentsEarlGreyTests.podspec index 398c1c8..27b7a23 100644 --- a/MaterialComponentsEarlGreyTests.podspec +++ b/MaterialComponentsEarlGreyTests.podspec
@@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MaterialComponentsEarlGreyTests" - s.version = "124.1.1" + s.version = "124.2.0" s.authors = "The Material Components authors." s.summary = "This spec is an aggregate of all the Material Components EarlGrey tests." s.description = "This spec is made for use in the MDC Catalog."
diff --git a/MaterialComponentsExamples.podspec b/MaterialComponentsExamples.podspec index eec5649..fc3acd9 100644 --- a/MaterialComponentsExamples.podspec +++ b/MaterialComponentsExamples.podspec
@@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MaterialComponentsExamples" - s.version = "124.1.1" + s.version = "124.2.0" s.authors = "The Material Components authors." s.summary = "This spec is an aggregate of all the Material Components examples." s.description = "This spec is made for use in the MDC Catalog. Used in conjunction with CatalogByConvention we create our Material Catalog."
diff --git a/MaterialComponentsSnapshotTests.podspec b/MaterialComponentsSnapshotTests.podspec index 0269fa4..5cbb704 100644 --- a/MaterialComponentsSnapshotTests.podspec +++ b/MaterialComponentsSnapshotTests.podspec
@@ -53,7 +53,7 @@ Pod::Spec.new do |s| s.name = "MaterialComponentsSnapshotTests" - s.version = "124.1.1" + s.version = "124.2.0" s.authors = "The Material Components authors." s.summary = "This spec is an aggregate of all the Material Components snapshot tests." s.homepage = "https://github.com/material-components/material-components-ios"
diff --git a/VERSION b/VERSION index e6afbd0..0dac7a9 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@ -124.1.1 +124.2.0
diff --git a/catalog/MDCCatalog/Info.plist b/catalog/MDCCatalog/Info.plist index 36af393..7156046 100644 --- a/catalog/MDCCatalog/Info.plist +++ b/catalog/MDCCatalog/Info.plist
@@ -15,11 +15,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>124.1.1</string> + <string>124.2.0</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> - <string>124.1.1</string> + <string>124.2.0</string> <key>LSRequiresIPhoneOS</key> <true/> <key>UIAppFonts</key>
diff --git a/catalog/MDCCatalog/MDCCatalogComponentsController.swift b/catalog/MDCCatalog/MDCCatalogComponentsController.swift index a94087f..dbb40bd 100644 --- a/catalog/MDCCatalog/MDCCatalogComponentsController.swift +++ b/catalog/MDCCatalog/MDCCatalogComponentsController.swift
@@ -65,16 +65,15 @@ // "Use of undeclared type 'UIPointerInteractionDelegate'" // Ideally, we would be able to tie this to an iOS version rather than a compiler version, but // such a solution does not seem to be available for Swift. -#if compiler(>=5.2) + #if compiler(>=5.2) if #available(iOS 13.4, *) { let interaction = UIPointerInteraction(delegate: self) button.addInteraction(interaction) } -#endif + #endif return button }() - private let node: CBCNode private lazy var titleLabel: UILabel = { let titleLabel = UILabel() @@ -92,10 +91,11 @@ let layout = UICollectionViewFlowLayout() let sectionInset: CGFloat = Constants.spacing - layout.sectionInset = UIEdgeInsets(top: sectionInset, - left: sectionInset, - bottom: sectionInset, - right: sectionInset) + layout.sectionInset = UIEdgeInsets( + top: sectionInset, + left: sectionInset, + bottom: sectionInset, + right: sectionInset) layout.minimumInteritemSpacing = Constants.spacing layout.minimumLineSpacing = Constants.spacing @@ -111,7 +111,8 @@ headerViewController.headerView.maximumHeight = 128 headerViewController.headerView.minimumHeight = 56 - collectionView?.register(MDCCatalogCollectionViewCell.self, + collectionView?.register( + MDCCatalogCollectionViewCell.self, forCellWithReuseIdentifier: "MDCCatalogCollectionViewCell") collectionView?.backgroundColor = AppTheme.containerScheme.colorScheme.backgroundColor @@ -157,10 +158,11 @@ titleLabel.font = AppTheme.containerScheme.typographyScheme.headline6 titleLabel.sizeToFit() - let titleInsets = UIEdgeInsets(top: 0, - left: Constants.inset, - bottom: Constants.inset, - right: Constants.inset) + let titleInsets = UIEdgeInsets( + top: 0, + left: Constants.inset, + bottom: Constants.inset, + right: Constants.inset) let titleSize = titleLabel.sizeThatFits(containerView.bounds.size) containerView.addSubview(titleLabel) @@ -172,25 +174,29 @@ let colorScheme = AppTheme.containerScheme.colorScheme - let image = MDCDrawImage(CGRect(x:0, - y:0, - width: Constants.logoWidthHeight, - height: Constants.logoWidthHeight), - { MDCCatalogDrawMDCLogoLight($0, $1) }, - colorScheme) + let image = MDCDrawImage( + CGRect( + x: 0, + y: 0, + width: Constants.logoWidthHeight, + height: Constants.logoWidthHeight), + { MDCCatalogDrawMDCLogoLight($0, $1) }, + colorScheme) logo.image = image - menuButton.addTarget(self.navigationController, - action: #selector(navigationController?.presentMenu), - for: .touchUpInside) + menuButton.addTarget( + self.navigationController, + action: #selector(navigationController?.presentMenu), + for: .touchUpInside) menuButton.tintColor = colorScheme.onPrimaryColor containerView.addSubview(menuButton) setupFlexibleHeaderContentConstraints() - constrainLabel(label: titleLabel, - containerView: containerView, - insets: titleInsets, - height: titleSize.height) + constrainLabel( + label: titleLabel, + containerView: containerView, + insets: titleInsets, + height: titleSize.height) headerViewController.headerView.backgroundColor = colorScheme.primaryColor @@ -207,7 +213,7 @@ view.addSubview(headerViewController.view) headerViewController.didMove(toParent: self) - collectionView?.accessibilityIdentifier = "collectionView" + collectionView?.accessibilityIdentifier = "componentList" if #available(iOS 11.0, *) { collectionView?.contentInsetAdjustmentBehavior = .always } @@ -220,7 +226,8 @@ } override func willAnimateRotation( - to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) { + to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval + ) { collectionView?.collectionViewLayout.invalidateLayout() } @@ -242,69 +249,82 @@ func setupFlexibleHeaderContentConstraints() { - logoLeftPaddingConstraint = NSLayoutConstraint(item: logo, - attribute: .leading, - relatedBy: .equal, - toItem: logo.superview, - attribute: .leading, - multiplier: 1, - constant: Constants.inset) + logoLeftPaddingConstraint = NSLayoutConstraint( + item: logo, + attribute: .leading, + relatedBy: .equal, + toItem: logo.superview, + attribute: .leading, + multiplier: 1, + constant: Constants.inset) logoLeftPaddingConstraint?.isActive = true - menuButtonRightPaddingConstraint = NSLayoutConstraint(item: menuButton, - attribute: .trailing, - relatedBy: .equal, - toItem: menuButton.superview, - attribute: .trailing, - multiplier: 1, - constant: -1 * Constants.inset) + menuButtonRightPaddingConstraint = NSLayoutConstraint( + item: menuButton, + attribute: .trailing, + relatedBy: .equal, + toItem: menuButton.superview, + attribute: .trailing, + multiplier: 1, + constant: -1 * Constants.inset) menuButtonRightPaddingConstraint?.isActive = true - menuTopPaddingConstraint = NSLayoutConstraint(item: menuButton, - attribute: .top, - relatedBy: .equal, - toItem: menuButton.superview, - attribute: .top, - multiplier: 1, - constant: Constants.menuTopVerticalSpacing) + menuTopPaddingConstraint = NSLayoutConstraint( + item: menuButton, + attribute: .top, + relatedBy: .equal, + toItem: menuButton.superview, + attribute: .top, + multiplier: 1, + constant: Constants.menuTopVerticalSpacing) menuTopPaddingConstraint?.isActive = true - NSLayoutConstraint(item: logo, - attribute: .centerY, - relatedBy: .equal, - toItem: menuButton, - attribute: .centerY, - multiplier: 1, - constant: 0).isActive = true - NSLayoutConstraint(item: logo, - attribute: .width, - relatedBy: .equal, - toItem: logo, - attribute: .height, - multiplier: 1, - constant: 0).isActive = true - NSLayoutConstraint(item: logo, - attribute: .width, - relatedBy: .equal, - toItem: nil, - attribute: .notAnAttribute, - multiplier: 1, - constant: Constants.logoWidthHeight).isActive = true + NSLayoutConstraint( + item: logo, + attribute: .centerY, + relatedBy: .equal, + toItem: menuButton, + attribute: .centerY, + multiplier: 1, + constant: 0 + ).isActive = true + NSLayoutConstraint( + item: logo, + attribute: .width, + relatedBy: .equal, + toItem: logo, + attribute: .height, + multiplier: 1, + constant: 0 + ).isActive = true + NSLayoutConstraint( + item: logo, + attribute: .width, + relatedBy: .equal, + toItem: nil, + attribute: .notAnAttribute, + multiplier: 1, + constant: Constants.logoWidthHeight + ).isActive = true - NSLayoutConstraint(item: menuButton, - attribute: .width, - relatedBy: .equal, - toItem: menuButton, - attribute: .height, - multiplier: 1, - constant: 0).isActive = true - NSLayoutConstraint(item: menuButton, - attribute: .width, - relatedBy: .equal, - toItem: nil, - attribute: .notAnAttribute, - multiplier: 1, - constant: Constants.menuButtonWidthHeight).isActive = true + NSLayoutConstraint( + item: menuButton, + attribute: .width, + relatedBy: .equal, + toItem: menuButton, + attribute: .height, + multiplier: 1, + constant: 0 + ).isActive = true + NSLayoutConstraint( + item: menuButton, + attribute: .width, + relatedBy: .equal, + toItem: nil, + attribute: .notAnAttribute, + multiplier: 1, + constant: Constants.menuButtonWidthHeight + ).isActive = true } // MARK: UICollectionViewDataSource @@ -313,8 +333,10 @@ return 1 } - override func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { + override func collectionView( + _ collectionView: UICollectionView, + numberOfItemsInSection section: Int + ) -> Int { return node.children.count } @@ -340,11 +362,14 @@ // MARK: UICollectionViewDelegate - override func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + override func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { let cell = - collectionView.dequeueReusableCell(withReuseIdentifier: "MDCCatalogCollectionViewCell", - for: indexPath) + collectionView.dequeueReusableCell( + withReuseIdentifier: "MDCCatalogCollectionViewCell", + for: indexPath) cell.backgroundColor = AppTheme.containerScheme.colorScheme.backgroundColor let componentName = node.children[indexPath.row].title @@ -358,9 +383,11 @@ return cell } - func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath) -> CGSize { + func collectionView( + _ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath + ) -> CGSize { let dividerWidth: CGFloat = 1 var safeInsets: CGFloat = 0 if #available(iOS 11, *) { @@ -381,8 +408,10 @@ return CGSize(width: cellWidthHeight, height: cellWidthHeight) } - override func collectionView(_ collectionView: UICollectionView, - didSelectItemAt indexPath: IndexPath) { + override func collectionView( + _ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath + ) { let node = self.node.children[indexPath.row] var vc: UIViewController if node.isExample() { @@ -395,42 +424,52 @@ } // MARK: Private - func constrainLabel(label: UILabel, - containerView: UIView, - insets: UIEdgeInsets, - height: CGFloat) { + func constrainLabel( + label: UILabel, + containerView: UIView, + insets: UIEdgeInsets, + height: CGFloat + ) { - NSLayoutConstraint(item: label, - attribute: .leading, - relatedBy: .equal, - toItem: logo, - attribute: .trailing, - multiplier: 1.0, - constant: insets.left).isActive = true + NSLayoutConstraint( + item: label, + attribute: .leading, + relatedBy: .equal, + toItem: logo, + attribute: .trailing, + multiplier: 1.0, + constant: insets.left + ).isActive = true - NSLayoutConstraint(item: label, - attribute: .trailing, - relatedBy: .equal, - toItem: menuButton, - attribute: .leading, - multiplier: 1.0, - constant: -insets.right).isActive = true + NSLayoutConstraint( + item: label, + attribute: .trailing, + relatedBy: .equal, + toItem: menuButton, + attribute: .leading, + multiplier: 1.0, + constant: -insets.right + ).isActive = true - NSLayoutConstraint(item: label, - attribute: .bottom, - relatedBy: .equal, - toItem: containerView, - attribute: .bottom, - multiplier: 1.0, - constant: -insets.bottom).isActive = true + NSLayoutConstraint( + item: label, + attribute: .bottom, + relatedBy: .equal, + toItem: containerView, + attribute: .bottom, + multiplier: 1.0, + constant: -insets.bottom + ).isActive = true - NSLayoutConstraint(item: label, - attribute: .height, - relatedBy: .equal, - toItem: nil, - attribute: .notAnAttribute, - multiplier: 1.0, - constant: height).isActive = true + NSLayoutConstraint( + item: label, + attribute: .height, + relatedBy: .equal, + toItem: nil, + attribute: .notAnAttribute, + multiplier: 1.0, + constant: height + ).isActive = true } } @@ -439,19 +478,21 @@ // Ideally, we would be able to tie this to an iOS version rather than a compiler version, but such // a solution does not seem to be available for Swift. #if compiler(>=5.2) -@available(iOS 13.4, *) -extension MDCCatalogComponentsController: UIPointerInteractionDelegate { @available(iOS 13.4, *) - func pointerInteraction(_ interaction: UIPointerInteraction, - styleFor region: UIPointerRegion) -> UIPointerStyle? { - guard let interactionView = interaction.view else { - return nil + extension MDCCatalogComponentsController: UIPointerInteractionDelegate { + @available(iOS 13.4, *) + func pointerInteraction( + _ interaction: UIPointerInteraction, + styleFor region: UIPointerRegion + ) -> UIPointerStyle? { + guard let interactionView = interaction.view else { + return nil + } + let targetedPreview = UITargetedPreview(view: interactionView) + let pointerStyle = UIPointerStyle(effect: .highlight(targetedPreview)) + return pointerStyle } - let targetedPreview = UITargetedPreview(view: interactionView) - let pointerStyle = UIPointerStyle(effect: .highlight(targetedPreview)) - return pointerStyle } -} #endif // UIScrollViewDelegate @@ -464,8 +505,9 @@ } override func scrollViewDidEndDragging( - _ scrollView: UIScrollView, - willDecelerate decelerate: Bool) { + _ scrollView: UIScrollView, + willDecelerate decelerate: Bool + ) { let headerView = headerViewController.headerView if scrollView == headerView.trackingScrollView { headerView.trackingScrollDidEndDraggingWillDecelerate(decelerate) @@ -479,9 +521,10 @@ } override func scrollViewWillEndDragging( - _ scrollView: UIScrollView, - withVelocity velocity: CGPoint, - targetContentOffset: UnsafeMutablePointer<CGPoint>) { + _ scrollView: UIScrollView, + withVelocity velocity: CGPoint, + targetContentOffset: UnsafeMutablePointer<CGPoint> + ) { let headerView = headerViewController.headerView if scrollView == headerView.trackingScrollView { headerView.trackingScrollWillEndDragging(
diff --git a/catalog/MDCDragons/Info.plist b/catalog/MDCDragons/Info.plist index 3dc3c83..900bdf0 100644 --- a/catalog/MDCDragons/Info.plist +++ b/catalog/MDCDragons/Info.plist
@@ -15,9 +15,9 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>124.1.1</string> + <string>124.2.0</string> <key>CFBundleVersion</key> - <string>124.1.1</string> + <string>124.2.0</string> <key>LSRequiresIPhoneOS</key> <true/> <key>UILaunchStoryboardName</key>
diff --git a/catalog/MaterialCatalog/MaterialCatalog.podspec b/catalog/MaterialCatalog/MaterialCatalog.podspec index 666c4d1..a1c80ef 100644 --- a/catalog/MaterialCatalog/MaterialCatalog.podspec +++ b/catalog/MaterialCatalog/MaterialCatalog.podspec
@@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MaterialCatalog" - s.version = "124.1.1" + s.version = "124.2.0" s.summary = "Helper Objective-C classes for the MDC catalog." s.description = "This spec is made for use in the MDC Catalog." s.homepage = "https://github.com/material-components/material-components-ios"
diff --git a/catalog/Podfile b/catalog/Podfile index d346e1a..b6a8879 100644 --- a/catalog/Podfile +++ b/catalog/Podfile
@@ -13,9 +13,7 @@ 'ActivityIndicator/UnitTests', 'AnimationTiming/UnitTests', 'AppBar/UnitTests', - 'AppBar+Theming/UnitTests', 'Banner/UnitTests', - 'Banner+Theming/UnitTests', 'BottomAppBar/UnitTests', 'BottomNavigation/UnitTests', 'BottomNavigation+BottomNavigationController/UnitTests', @@ -23,16 +21,12 @@ 'BottomSheet/UnitTests', 'ButtonBar/UnitTests', 'Buttons/UnitTests', - 'Buttons+Theming/UnitTests', 'Cards/UnitTests', - 'Cards+Theming/UnitTests', 'Chips/UnitTests', - 'Chips+Theming/UnitTests', 'CollectionCells/UnitTests', 'CollectionLayoutAttributes/UnitTests', 'Collections/UnitTests', 'Dialogs/UnitTests', - 'Dialogs+Theming/UnitTests', 'Elevation/UnitTests', 'FeatureHighlight/UnitTests', 'FlexibleHeader/UnitTests', @@ -40,7 +34,6 @@ 'Ink/UnitTests', 'LibraryInfo/UnitTests', 'List/UnitTests', - 'List+Theming/UnitTests', 'NavigationBar/UnitTests', 'NavigationDrawer/UnitTests', 'OverlayWindow/UnitTests', @@ -72,7 +65,6 @@ 'Tabs+Theming/UnitTests', 'Tabs+TabBarView/UnitTests', 'TextFields/UnitTests', - 'TextFields+Theming/UnitTests', 'TextControls+BaseTextAreas/UnitTests', 'TextControls+BaseTextFields/UnitTests', 'TextControls+FilledTextAreas/UnitTests',
diff --git a/components/ActionSheet/src/MDCActionSheetController.h b/components/ActionSheet/src/MDCActionSheetController.h index 9991f7c..d6483b3 100644 --- a/components/ActionSheet/src/MDCActionSheetController.h +++ b/components/ActionSheet/src/MDCActionSheetController.h
@@ -94,6 +94,13 @@ - (void)addAction:(nonnull MDCActionSheetAction *)action; /** + Returns the view associated with a given @c action. + + @param action The action used to create the view. + */ +- (nullable UIView *)viewForAction:(nonnull MDCActionSheetAction *)action; + +/** The object that acts as the delegate of the @c MDCActionSheetController */ @property(nonatomic, weak, nullable) id<MDCActionSheetControllerDelegate> delegate;
diff --git a/components/ActionSheet/src/MDCActionSheetController.m b/components/ActionSheet/src/MDCActionSheetController.m index c5f6fd7..11b78ed 100644 --- a/components/ActionSheet/src/MDCActionSheetController.m +++ b/components/ActionSheet/src/MDCActionSheetController.m
@@ -18,8 +18,11 @@ #import "private/MDCActionSheetItemTableViewCell.h" #import "private/MaterialActionSheetStrings.h" #import "private/MaterialActionSheetStrings_table.h" +#import "MDCActionSheetAction.h" #import "MDCActionSheetControllerDelegate.h" #import "MaterialAvailability.h" +#import "MaterialBottomSheet.h" +#import "MaterialElevation.h" #import "MaterialShadowElevations.h" #import "MaterialTypography.h" #import "MaterialMath.h" @@ -184,6 +187,16 @@ [self updateTable]; } +- (UIView *)viewForAction:(MDCActionSheetAction *)action { + if (![self.actions containsObject:action]) { + return nil; + } + [self.view layoutIfNeeded]; + NSUInteger rowIndex = [self.actions indexOfObject:action]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0]; + return [self.tableView cellForRowAtIndexPath:indexPath]; +} + - (NSArray<MDCActionSheetAction *> *)actions { return [_actions copy]; } @@ -293,7 +306,15 @@ if (!self.dismissOnBackgroundTap) { return NO; } - [self dismissViewControllerAnimated:YES completion:nil]; + [self + dismissViewControllerAnimated:YES + completion:^{ + if ([self.delegate + respondsToSelector:@selector + (actionSheetControllerDismissalAnimationCompleted:)]) { + [self.delegate actionSheetControllerDismissalAnimationCompleted:self]; + } + }]; return YES; }
diff --git a/components/ActionSheet/tests/snapshot/MDCActionSheetControllerViewForActionSnapshotTests.m b/components/ActionSheet/tests/snapshot/MDCActionSheetControllerViewForActionSnapshotTests.m new file mode 100644 index 0000000..e1f5ff5 --- /dev/null +++ b/components/ActionSheet/tests/snapshot/MDCActionSheetControllerViewForActionSnapshotTests.m
@@ -0,0 +1,115 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 "MaterialSnapshot.h" + +#import "MaterialActionSheet.h" + +/** + Snapshot test for the @c viewForAction: API. + */ +@interface MDCActionSheetControllerViewForActionSnapshotTests : MDCSnapshotTestCase +/** The @c MDCActionSheetController being tested. */ +@property(nonatomic, strong, nullable) MDCActionSheetController *actionSheet; + +/** An Action Sheet action. */ +@property(nonatomic, strong) MDCActionSheetAction *action1; + +/** An Action Sheet action. */ +@property(nonatomic, strong) MDCActionSheetAction *action2; + +@end + +@implementation MDCActionSheetControllerViewForActionSnapshotTests + +- (void)setUp { + [super setUp]; + + // Uncomment below to recreate all the goldens (or add the following line to the specific + // test you wish to recreate the golden for). + // self.recordMode = YES; + + self.actionSheet = [[MDCActionSheetController alloc] init]; + self.action1 = [MDCActionSheetAction + actionWithTitle:@"Foo" + image:[UIImage mdc_testImageOfSize:CGSizeMake(24, 24) + withStyle:MDCSnapshotTestImageStyleCheckerboard] + handler:nil]; + self.action2 = [MDCActionSheetAction + actionWithTitle:@"Bar" + image:[UIImage mdc_testImageOfSize:CGSizeMake(24, 24) + withStyle:MDCSnapshotTestImageStyleEllipses] + handler:nil]; +} + +- (void)tearDown { + if (self.actionSheet.presentingViewController) { + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Action sheet is dismissed"]; + [self.actionSheet dismissViewControllerAnimated:NO + completion:^{ + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:5]; + } + self.action1 = nil; + self.action2 = nil; + self.actionSheet = nil; + + [super tearDown]; +} + +- (void)testOneActionAddedToActionSheet { + // Given + [self.actionSheet addAction:self.action1]; + + // When + UIView *view = [self.actionSheet viewForAction:self.action1]; + + // Then + [self generateSnapshotAndVerifyForView:view]; +} + +- (void)testMultipleActionsAddedToActionSheetViewForFirstIndex { + // Given + [self.actionSheet addAction:self.action1]; + [self.actionSheet addAction:self.action2]; + + // When + UIView *view = [self.actionSheet viewForAction:self.action1]; + + // Then + [self generateSnapshotAndVerifyForView:view]; +} + +- (void)testMultipleActionsAddedToActionSheetViewForLastIndex { + // Given + [self.actionSheet addAction:self.action1]; + [self.actionSheet addAction:self.action2]; + + // When + UIView *view = [self.actionSheet viewForAction:self.action2]; + + // Then + [self generateSnapshotAndVerifyForView:view]; +} + +#pragma mark - Helpers + +- (void)generateSnapshotAndVerifyForView:(UIView *)view { + UIView *snapshotView = [view mdc_addToBackgroundView]; + [self snapshotVerifyView:snapshotView]; +} + +@end
diff --git a/components/ActionSheet/tests/unit/MDCActionSheetControllerTests.m b/components/ActionSheet/tests/unit/MDCActionSheetControllerTests.m index 13c6d2f..dc8be1f 100644 --- a/components/ActionSheet/tests/unit/MDCActionSheetControllerTests.m +++ b/components/ActionSheet/tests/unit/MDCActionSheetControllerTests.m
@@ -569,4 +569,58 @@ XCTAssertGreaterThan(self.actionSheet.tableView.contentInset.top, originalTableContentInset); } +- (void)testViewForActionWhenNoActionsAdded { + // Given + self.actionSheet.view.bounds = CGRectMake(0, 0, 500, 500); + MDCActionSheetAction *action = [MDCActionSheetAction actionWithTitle:@"Foo" + image:nil + handler:nil]; + + // When + UIView *view = [self.actionSheet viewForAction:action]; + + // Then + XCTAssertNil(view); +} + +- (void)testViewForActionWhenMultipleActionsAreAdded { + // Given + self.actionSheet.view.bounds = CGRectMake(0, 0, 500, 500); + MDCActionSheetAction *actionOne = [MDCActionSheetAction actionWithTitle:@"Foo" + image:nil + handler:nil]; + MDCActionSheetAction *actionTwo = [MDCActionSheetAction actionWithTitle:@"Bar" + image:nil + handler:nil]; + [self.actionSheet addAction:actionOne]; + [self.actionSheet addAction:actionTwo]; + + // When + UIView *view = [self.actionSheet viewForAction:actionTwo]; + + // Then + XCTAssertNotNil(view); +} + +- (void)testViewForActionWhenActionHasNotBeenAddedThenAdded { + // Given + self.actionSheet.view.bounds = CGRectMake(0, 0, 500, 500); + MDCActionSheetAction *action = [MDCActionSheetAction actionWithTitle:@"Foo" + image:nil + handler:nil]; + + // When + UIView *view = [self.actionSheet viewForAction:action]; + + // Then + XCTAssertNil(view); + + // When + [self.actionSheet addAction:action]; + view = [self.actionSheet viewForAction:action]; + + // Then + XCTAssertNotNil(view); +} + @end
diff --git a/components/ActivityIndicator/src/MDCActivityIndicator+Interface.h b/components/ActivityIndicator/src/MDCActivityIndicator+Interface.h new file mode 100644 index 0000000..42c2e84 --- /dev/null +++ b/components/ActivityIndicator/src/MDCActivityIndicator+Interface.h
@@ -0,0 +1,185 @@ +// Copyright 2016-present the Material Components for iOS authors. 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. + +// IWYU pragma: private + +#import <UIKit/UIKit.h> + +@class MDCActivityIndicatorTransition; +@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://material.io/go/design-progress-indicators + */ +IB_DESIGNABLE +@interface MDCActivityIndicator : UIView + +/** + The callback delegate. See @c MDCActivityIndicatorDelegate. + */ +@property(nonatomic, weak, nullable) id<MDCActivityIndicatorDelegate> 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), with a minimum of 5dp. 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 2.5. + */ +@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; + +/** + Set the determinate progress of the activity indicator when indicatorMode is + MDCActivityIndicatorModeDeterminate. + */ +- (void)setProgress:(float)progress animated:(BOOL)animated; + +/** + The array of colors that are cycled through when animating the spinner. Populated with a set of + default colors. + + @note If an empty array is provided to this property's setter, then the provided array will be + discarded and an array consisting of the default color values will be assigned instead. + */ +@property(nonatomic, copy, nonnull) NSArray<UIColor *> *cycleColors UI_APPEARANCE_SELECTOR; + +/** + Starts the animated activity indicator. Does nothing if the spinner is already animating. + */ +- (void)startAnimating; + +/** + Starts the animated activity indicator after performing the provided transition. The animation + cycle will begin on the cycleStartIndex provided. The startTransition will be applied with the + starting and ending positions of the indicator stroke at the moment when the animation will begin + taking into account the provided cycleStartIndex in the range [0,1]. The indicatorMode must be + MDCActivityIndicatorModeIndeterminate before calling. + */ +- (void)startAnimatingWithTransition:(nonnull MDCActivityIndicatorTransition *)startTransition + cycleStartIndex:(NSInteger)cycleStartIndex; + +/** + Stops the animated activity indicator with a short opacity and stroke width animation. Does nothing + if the spinner is not animating. + */ +- (void)stopAnimating; + +/** + Stops the animated activity indicator and then performs the provided transition. The provided + stopTransition will be called with the starting and ending positions of the indicator stroke at the + moment when the animation will begin in the range [0,1]. The indicatorMode must be + MDCActivityIndicatorModeIndeterminate before calling. + */ +- (void)stopAnimatingWithTransition:(nonnull MDCActivityIndicatorTransition *)stopTransition; + +/** + A block that is invoked when the @c MDCActivityIndicator receives a call to @c + traitCollectionDidChange:. The block is called after the call to the superclass. + */ +@property(nonatomic, copy, nullable) void (^traitCollectionDidChangeBlock) + (MDCActivityIndicator *_Nonnull activityIndicator, + UITraitCollection *_Nullable previousTraitCollection); + +@end +typedef void (^MDCActivityIndicatorAnimation)(CGFloat strokeStart, CGFloat strokeEnd); + +/** + Describes an animation that can be provided to an MDCActivityIndicator instance to perform before + or after its standard cycle animation. + */ +@interface MDCActivityIndicatorTransition : NSObject + +/** + The animations to be performed by MDCActivityIndicator. In this block add CAAnimations to be + animated before or after MDCActivityIndicator's cycle animation. MDCActivityIndicator will trigger + these animations and call completion after they complete. + */ +@property(nonatomic, copy, nonnull) MDCActivityIndicatorAnimation animation; + +/** + The completion block to call after animation's completion. This should be used to clean up any + layers placed and animating on the MDCActivityIndicator. + */ +@property(nonatomic, copy, nullable) void (^completion)(void); + +/** + The duration of the animation. + */ +@property(nonatomic, assign) NSTimeInterval duration; + +- (nonnull instancetype)init NS_UNAVAILABLE; + +- (nonnull instancetype)initWithCoder:(nonnull NSCoder *)aDecoder NS_UNAVAILABLE; + +- (nonnull instancetype)initWithAnimation:(_Nonnull MDCActivityIndicatorAnimation)animation + NS_DESIGNATED_INITIALIZER; + +@end
diff --git a/components/ActivityIndicator/src/MDCActivityIndicator.h b/components/ActivityIndicator/src/MDCActivityIndicator.h index 7ec0af1..e54db19 100644 --- a/components/ActivityIndicator/src/MDCActivityIndicator.h +++ b/components/ActivityIndicator/src/MDCActivityIndicator.h
@@ -12,172 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import <UIKit/UIKit.h> - -@class MDCActivityIndicatorTransition; -@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://material.io/go/design-progress-indicators - */ -IB_DESIGNABLE -@interface MDCActivityIndicator : UIView - -/** - The callback delegate. See @c MDCActivityIndicatorDelegate. - */ -@property(nonatomic, weak, nullable) id<MDCActivityIndicatorDelegate> 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), with a minimum of 5dp. 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 2.5. - */ -@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; - -/** - Set the determinate progress of the activity indicator when indicatorMode is - MDCActivityIndicatorModeDeterminate. - */ -- (void)setProgress:(float)progress animated:(BOOL)animated; - -/** - The array of colors that are cycled through when animating the spinner. Populated with a set of - default colors. - - @note If an empty array is provided to this property's setter, then the provided array will be - discarded and an array consisting of the default color values will be assigned instead. - */ -@property(nonatomic, copy, nonnull) NSArray<UIColor *> *cycleColors UI_APPEARANCE_SELECTOR; - -/** - Starts the animated activity indicator. Does nothing if the spinner is already animating. - */ -- (void)startAnimating; - -/** - Starts the animated activity indicator after performing the provided transition. The animation - cycle will begin on the cycleStartIndex provided. The startTransition will be applied with the - starting and ending positions of the indicator stroke at the moment when the animation will begin - taking into account the provided cycleStartIndex in the range [0,1]. The indicatorMode must be - MDCActivityIndicatorModeIndeterminate before calling. - */ -- (void)startAnimatingWithTransition:(nonnull MDCActivityIndicatorTransition *)startTransition - cycleStartIndex:(NSInteger)cycleStartIndex; - -/** - Stops the animated activity indicator with a short opacity and stroke width animation. Does nothing - if the spinner is not animating. - */ -- (void)stopAnimating; - -/** - Stops the animated activity indicator and then performs the provided transition. The provided - stopTransition will be called with the starting and ending positions of the indicator stroke at the - moment when the animation will begin in the range [0,1]. The indicatorMode must be - MDCActivityIndicatorModeIndeterminate before calling. - */ -- (void)stopAnimatingWithTransition:(nonnull MDCActivityIndicatorTransition *)stopTransition; - -/** - A block that is invoked when the @c MDCActivityIndicator receives a call to @c - traitCollectionDidChange:. The block is called after the call to the superclass. - */ -@property(nonatomic, copy, nullable) void (^traitCollectionDidChangeBlock) - (MDCActivityIndicator *_Nonnull activityIndicator, - UITraitCollection *_Nullable previousTraitCollection); - -@end -typedef void (^MDCActivityIndicatorAnimation)(CGFloat strokeStart, CGFloat strokeEnd); - -/** - Describes an animation that can be provided to an MDCActivityIndicator instance to perform before - or after its standard cycle animation. - */ -@interface MDCActivityIndicatorTransition : NSObject - -/** - The animations to be performed by MDCActivityIndicator. In this block add CAAnimations to be - animated before or after MDCActivityIndicator's cycle animation. MDCActivityIndicator will trigger - these animations and call completion after they complete. - */ -@property(nonatomic, copy, nonnull) MDCActivityIndicatorAnimation animation; - -/** - The completion block to call after animation's completion. This should be used to clean up any - layers placed and animating on the MDCActivityIndicator. - */ -@property(nonatomic, copy, nullable) void (^completion)(void); - -/** - The duration of the animation. - */ -@property(nonatomic, assign) NSTimeInterval duration; - -- (nonnull instancetype)init NS_UNAVAILABLE; - -- (nonnull instancetype)initWithCoder:(nonnull NSCoder *)aDecoder NS_UNAVAILABLE; - -- (nonnull instancetype)initWithAnimation:(_Nonnull MDCActivityIndicatorAnimation)animation - NS_DESIGNATED_INITIALIZER; - -@end +#import "MDCActivityIndicator+Interface.h" // IWYU pragma: export
diff --git a/components/ActivityIndicator/src/private/MDCActivityIndicator+Private.h b/components/ActivityIndicator/src/private/MDCActivityIndicator+Private.h index 6f55f85..8f932f6 100644 --- a/components/ActivityIndicator/src/private/MDCActivityIndicator+Private.h +++ b/components/ActivityIndicator/src/private/MDCActivityIndicator+Private.h
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "MDCActivityIndicator.h" +#import "MDCActivityIndicator+Interface.h" /* States for the internal state machine. The states represent the last animation completed.
diff --git a/components/AppBar/src/MDCAppBarViewController.h b/components/AppBar/src/MDCAppBarViewController.h index c793e69..f81ef4c 100644 --- a/components/AppBar/src/MDCAppBarViewController.h +++ b/components/AppBar/src/MDCAppBarViewController.h
@@ -23,6 +23,7 @@ MDCAppBarViewController is a flexible header view controller that manages a navigation bar and header stack view in order to provide the Material Top App Bar user interface. */ +API_UNAVAILABLE(tvos, watchos) @interface MDCAppBarViewController : MDCFlexibleHeaderViewController /** @@ -83,6 +84,7 @@ @warning This API will be deprecated in favor of MDCAppBarViewController. Learn more at https://github.com/material-components/material-components-ios/blob/develop/components/AppBar/docs/migration-guide-appbar-appbarviewcontroller.md */ +API_UNAVAILABLE(tvos, watchos) @interface MDCAppBar : NSObject /**
diff --git a/components/AppBar/src/MDCAppBarViewControllerAccessibilityPerformEscapeDelegate.h b/components/AppBar/src/MDCAppBarViewControllerAccessibilityPerformEscapeDelegate.h index 2513054..720e3fc 100644 --- a/components/AppBar/src/MDCAppBarViewControllerAccessibilityPerformEscapeDelegate.h +++ b/components/AppBar/src/MDCAppBarViewControllerAccessibilityPerformEscapeDelegate.h
@@ -20,6 +20,7 @@ A delegate that can be implemented in order to respond to events specific to MDCAppBarViewController. */ +API_UNAVAILABLE(tvos, watchos) @protocol MDCAppBarViewControllerAccessibilityPerformEscapeDelegate <NSObject> @required
diff --git a/components/AppBar/tests/unit/Theming/MDCAppBarViewController_MaterialThemingTests.m b/components/AppBar/tests/unit/MDCAppBarViewController_MaterialThemingTests.m similarity index 97% rename from components/AppBar/tests/unit/Theming/MDCAppBarViewController_MaterialThemingTests.m rename to components/AppBar/tests/unit/MDCAppBarViewController_MaterialThemingTests.m index c70272d..4535cc7 100644 --- a/components/AppBar/tests/unit/Theming/MDCAppBarViewController_MaterialThemingTests.m +++ b/components/AppBar/tests/unit/MDCAppBarViewController_MaterialThemingTests.m
@@ -12,10 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +#import "MaterialAppBar.h" #import "MaterialAppBar+Theming.h" #import <XCTest/XCTest.h> +#import "MaterialFlexibleHeader.h" +#import "MaterialNavigationBar.h" +#import "MaterialShadowLayer.h" #import "MaterialColorScheme.h" #import "MaterialContainerScheme.h" #import "MaterialTypographyScheme.h"
diff --git a/components/Backdrop/.jazzy.yaml b/components/Backdrop/.jazzy.yaml deleted file mode 100644 index 6f4026a..0000000 --- a/components/Backdrop/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: Backdrop -umbrella_header: src/MaterialBackdrop.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/Backdrop/README.md b/components/Backdrop/README.md deleted file mode 100644 index c77db6f..0000000 --- a/components/Backdrop/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -# Backdrop - -The [Backdrop component](https://material.io/go/design-backdrop) is yet to be completed, please follow the [tracking issue](https://www.pivotaltracker.com/epic/show/3949726) for more information. -
diff --git a/components/Banner/tests/snapshot/MDCBannerSnapshotTests.m b/components/Banner/tests/snapshot/MDCBannerSnapshotTests.m index 18dbd8f..d181372 100644 --- a/components/Banner/tests/snapshot/MDCBannerSnapshotTests.m +++ b/components/Banner/tests/snapshot/MDCBannerSnapshotTests.m
@@ -14,8 +14,8 @@ #import "MaterialSnapshot.h" -#import "MaterialBanner+Theming.h" #import "MaterialBanner.h" +#import "MaterialBanner+Theming.h" #import "MaterialButtons.h" #import "MaterialTypographyScheme.h" @@ -63,12 +63,9 @@ } - (UITraitCollection *)traitCollection { - if (@available(iOS 10.0, *)) { - UITraitCollection *traitCollection = [UITraitCollection - traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; - return traitCollection; - } - return [super traitCollection]; + UITraitCollection *traitCollection = [UITraitCollection + traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; + return traitCollection; } @end @@ -452,66 +449,62 @@ } - (void)testDynamicTypeForContentSizeCategoryExtraExtraLarge { - if (@available(iOS 10.0, *)) { - // Given - self.bannerView = [[MDCBannerView alloc] init]; - self.typographyScheme = - [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; + // Given + self.bannerView = [[MDCBannerView alloc] init]; + self.typographyScheme = + [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; - // When - self.bannerView.layoutMargins = UIEdgeInsetsMake(0, 8, 0, 8); - self.bannerView.textView.text = kBannerShortText; - self.bannerView.textView.font = self.typographyScheme.body2; - MDCButton *button = self.bannerView.leadingButton; - [button setTitle:@"Action" forState:UIControlStateNormal]; - [button setTitleFont:self.typographyScheme.button forState:UIControlStateNormal]; - button.uppercaseTitle = YES; - [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; - self.bannerView.trailingButton.hidden = YES; - self.bannerView.mdc_adjustsFontForContentSizeCategory = YES; + // When + self.bannerView.layoutMargins = UIEdgeInsetsMake(0, 8, 0, 8); + self.bannerView.textView.text = kBannerShortText; + self.bannerView.textView.font = self.typographyScheme.body2; + MDCButton *button = self.bannerView.leadingButton; + [button setTitle:@"Action" forState:UIControlStateNormal]; + [button setTitleFont:self.typographyScheme.button forState:UIControlStateNormal]; + button.uppercaseTitle = YES; + [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; + self.bannerView.trailingButton.hidden = YES; + self.bannerView.mdc_adjustsFontForContentSizeCategory = YES; - // Then - [self generateSnapshotWithContentSizeCategoryAndNotificationPost: - UIContentSizeCategoryExtraExtraLarge - andVerifyForView:self.bannerView]; - } + // Then + [self generateSnapshotWithContentSizeCategoryAndNotificationPost: + UIContentSizeCategoryExtraExtraLarge + andVerifyForView:self.bannerView]; } - (void)testDynamicTypeForAttributedTextStringWhenContentSizeCategoryIsExtraExtraLarge { - if (@available(iOS 10.0, *)) { - // Given - self.bannerView = [[MDCBannerView alloc] init]; - self.typographyScheme = - [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; - MDCButton *button = self.bannerView.leadingButton; - self.bannerView.layoutMargins = UIEdgeInsetsMake(0, 8, 0, 8); - [button setTitle:@"Action" forState:UIControlStateNormal]; - [button setTitleFont:self.typographyScheme.button forState:UIControlStateNormal]; - button.uppercaseTitle = YES; - [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; - self.bannerView.trailingButton.hidden = YES; + // Given + self.bannerView = [[MDCBannerView alloc] init]; + self.typographyScheme = + [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; + MDCButton *button = self.bannerView.leadingButton; + self.bannerView.layoutMargins = UIEdgeInsetsMake(0, 8, 0, 8); + [button setTitle:@"Action" forState:UIControlStateNormal]; + [button setTitleFont:self.typographyScheme.button forState:UIControlStateNormal]; + button.uppercaseTitle = YES; + [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; + self.bannerView.trailingButton.hidden = YES; - // When - NSMutableAttributedString *bannerString = - [[NSMutableAttributedString alloc] initWithString:kBannerShortText]; - [bannerString addAttribute:NSFontAttributeName - value:self.typographyScheme.body1 - range:NSMakeRange(10, 8)]; - [bannerString addAttribute:NSForegroundColorAttributeName - value:UIColor.redColor - range:NSMakeRange(0, 9)]; - [bannerString addAttribute:NSLinkAttributeName - value:@"http://www.google.com" - range:NSMakeRange([kBannerShortText length] - 2, 2)]; - self.bannerView.textView.attributedText = bannerString; - self.bannerView.textView.font = self.typographyScheme.body2; - self.bannerView.mdc_adjustsFontForContentSizeCategory = YES; + // When + NSMutableAttributedString *bannerString = + [[NSMutableAttributedString alloc] initWithString:kBannerShortText]; + [bannerString addAttribute:NSFontAttributeName + value:self.typographyScheme.body1 + range:NSMakeRange(10, 8)]; + [bannerString addAttribute:NSForegroundColorAttributeName + value:UIColor.redColor + range:NSMakeRange(0, 9)]; + [bannerString addAttribute:NSLinkAttributeName + value:@"http://www.google.com" + range:NSMakeRange([kBannerShortText length] - 2, 2)]; + self.bannerView.textView.attributedText = bannerString; + self.bannerView.textView.font = self.typographyScheme.body2; + self.bannerView.mdc_adjustsFontForContentSizeCategory = YES; - // Then - [self generateSnapshotWithContentSizeCategoryAndNotificationPost: - UIContentSizeCategoryExtraExtraLarge - andVerifyForView:self.bannerView]; - } + // Then + [self generateSnapshotWithContentSizeCategoryAndNotificationPost: + UIContentSizeCategoryExtraExtraLarge + andVerifyForView:self.bannerView]; } - (void)testPreferredFontForAXXLContentSizeCategory {
diff --git a/components/Banner/tests/unit/BannerViewTests.m b/components/Banner/tests/unit/BannerViewTests.m index b7d6606..ea59e3b 100644 --- a/components/Banner/tests/unit/BannerViewTests.m +++ b/components/Banner/tests/unit/BannerViewTests.m
@@ -45,12 +45,9 @@ } - (UITraitCollection *)traitCollection { - if (@available(iOS 10.0, *)) { - UITraitCollection *traitCollection = [UITraitCollection - traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; - return traitCollection; - } - return [super traitCollection]; + UITraitCollection *traitCollection = [UITraitCollection + traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; + return traitCollection; } @end @@ -74,38 +71,36 @@ } - (void)testBannerViewDynamicTypeBehavior { - if (@available(iOS 10.0, *)) { - // Given - self.banner.trailingButton.hidden = YES; - self.banner.mdc_adjustsFontForContentSizeCategory = YES; - UIFont *font = [UIFont systemFontOfSize:10.0 weight:UIFontWeightRegular]; - MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleBody2]; - UIFont *scalableFont = [fontScaler scaledFontWithFont:font]; - scalableFont = [scalableFont mdc_scaledFontAtDefaultSize]; - self.banner.textView.font = scalableFont; - self.banner.textView.text = @"Banner Text"; - CGFloat originalTextFontSize = self.banner.textView.font.pointSize; - MDCButton *leadingButton = self.banner.leadingButton; - [leadingButton setTitleFont:scalableFont forState:UIControlStateNormal]; - CGFloat originalButtonFontSize = - [self.banner.leadingButton titleFontForState:UIControlStateNormal].pointSize; + // Given + self.banner.trailingButton.hidden = YES; + self.banner.mdc_adjustsFontForContentSizeCategory = YES; + UIFont *font = [UIFont systemFontOfSize:10.0 weight:UIFontWeightRegular]; + MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleBody2]; + UIFont *scalableFont = [fontScaler scaledFontWithFont:font]; + scalableFont = [scalableFont mdc_scaledFontAtDefaultSize]; + self.banner.textView.font = scalableFont; + self.banner.textView.text = @"Banner Text"; + CGFloat originalTextFontSize = self.banner.textView.font.pointSize; + MDCButton *leadingButton = self.banner.leadingButton; + [leadingButton setTitleFont:scalableFont forState:UIControlStateNormal]; + CGFloat originalButtonFontSize = + [self.banner.leadingButton titleFontForState:UIControlStateNormal].pointSize; - // When - MDCBannerViewTestsDynamicTypeContentSizeCategoryOverrideWindow *extraExtraLargeContainer = - [[MDCBannerViewTestsDynamicTypeContentSizeCategoryOverrideWindow alloc] - initWithContentSizeCategoryOverride:UIContentSizeCategoryExtraExtraLarge]; - [extraExtraLargeContainer addSubview:self.banner]; - [NSNotificationCenter.defaultCenter - postNotificationName:UIContentSizeCategoryDidChangeNotification - object:nil]; + // When + MDCBannerViewTestsDynamicTypeContentSizeCategoryOverrideWindow *extraExtraLargeContainer = + [[MDCBannerViewTestsDynamicTypeContentSizeCategoryOverrideWindow alloc] + initWithContentSizeCategoryOverride:UIContentSizeCategoryExtraExtraLarge]; + [extraExtraLargeContainer addSubview:self.banner]; + [NSNotificationCenter.defaultCenter + postNotificationName:UIContentSizeCategoryDidChangeNotification + object:nil]; - // Then - CGFloat actualTextFontSize = self.banner.textView.font.pointSize; - XCTAssertGreaterThan(actualTextFontSize, originalTextFontSize); - CGFloat actualButtonFontSize = - [self.banner.leadingButton titleFontForState:UIControlStateNormal].pointSize; - XCTAssertGreaterThan(actualButtonFontSize, originalButtonFontSize); - } + // Then + CGFloat actualTextFontSize = self.banner.textView.font.pointSize; + XCTAssertGreaterThan(actualTextFontSize, originalTextFontSize); + CGFloat actualButtonFontSize = + [self.banner.leadingButton titleFontForState:UIControlStateNormal].pointSize; + XCTAssertGreaterThan(actualButtonFontSize, originalButtonFontSize); } - (void)testTraitCollectionDidChangeBlockCalledWithExpectedParameters {
diff --git a/components/Banner/tests/unit/Theming/MDCBannerViewThemingTests.m b/components/Banner/tests/unit/MDCBannerViewThemingTests.m similarity index 88% rename from components/Banner/tests/unit/Theming/MDCBannerViewThemingTests.m rename to components/Banner/tests/unit/MDCBannerViewThemingTests.m index e0afa71..420dcd7 100644 --- a/components/Banner/tests/unit/Theming/MDCBannerViewThemingTests.m +++ b/components/Banner/tests/unit/MDCBannerViewThemingTests.m
@@ -15,11 +15,14 @@ #import <XCTest/XCTest.h> #import "MaterialAvailability.h" -#import "MaterialBanner+Theming.h" #import "MaterialBanner.h" -#import "MaterialContainerScheme.h" -#import "MaterialMath.h" +#import "MaterialBanner+Theming.h" +#import "MaterialButtons.h" #import "UIColor+MaterialDynamic.h" +#import "MaterialMath.h" +#import "MaterialColorScheme.h" +#import "MaterialContainerScheme.h" +#import "MaterialTypographyScheme.h" // The opacity value applied to text view. static CGFloat const kTextViewOpacity = (CGFloat)0.87; @@ -56,12 +59,9 @@ } - (UITraitCollection *)traitCollection { - if (@available(iOS 10.0, *)) { - UITraitCollection *traitCollection = [UITraitCollection - traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; - return traitCollection; - } - return [super traitCollection]; + UITraitCollection *traitCollection = [UITraitCollection + traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; + return traitCollection; } @end @@ -190,27 +190,24 @@ } - (void)testFontsAreScaledWhenTypographySchemeRequestsPrescaling { - if (@available(iOS 10.0, *)) { - // Given - self.containerScheme.typographyScheme = - [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; - self.containerScheme.typographyScheme.useCurrentContentSizeCategoryWhenApplied = YES; + // Given + self.containerScheme.typographyScheme = + [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; + self.containerScheme.typographyScheme.useCurrentContentSizeCategoryWhenApplied = YES; - // When - MDCBannerViewThemingTestsDynamicTypeContentSizeCategoryOverrideWindow - *extraExtraLargeContainer = - [[MDCBannerViewThemingTestsDynamicTypeContentSizeCategoryOverrideWindow alloc] - initWithContentSizeCategoryOverride:UIContentSizeCategoryExtraExtraLarge]; - [extraExtraLargeContainer addSubview:self.bannerView]; - [NSNotificationCenter.defaultCenter - postNotificationName:UIContentSizeCategoryDidChangeNotification - object:nil]; - [self.bannerView applyThemeWithScheme:self.containerScheme]; + // When + MDCBannerViewThemingTestsDynamicTypeContentSizeCategoryOverrideWindow *extraExtraLargeContainer = + [[MDCBannerViewThemingTestsDynamicTypeContentSizeCategoryOverrideWindow alloc] + initWithContentSizeCategoryOverride:UIContentSizeCategoryExtraExtraLarge]; + [extraExtraLargeContainer addSubview:self.bannerView]; + [NSNotificationCenter.defaultCenter + postNotificationName:UIContentSizeCategoryDidChangeNotification + object:nil]; + [self.bannerView applyThemeWithScheme:self.containerScheme]; - // Then - XCTAssertGreaterThan(self.bannerView.textView.font.pointSize, - self.containerScheme.typographyScheme.body2.pointSize); - } + // Then + XCTAssertGreaterThan(self.bannerView.textView.font.pointSize, + self.containerScheme.typographyScheme.body2.pointSize); } - (void)testBannerViewBackgroundColorChangeWhenUIUserInterfaceStyleChangesOnIOS13 {
diff --git a/components/BottomNavigation/examples/BottomNavigationBarControllerExampleViewController.swift b/components/BottomNavigation/examples/BottomNavigationBarControllerExampleViewController.swift index 2a65b04..3a42095 100644 --- a/components/BottomNavigation/examples/BottomNavigationBarControllerExampleViewController.swift +++ b/components/BottomNavigation/examples/BottomNavigationBarControllerExampleViewController.swift
@@ -89,6 +89,7 @@ } } +@available(iOS 12, *) class BottomNavigationControllerExampleViewController: MDCBottomNavigationBarController { var containerScheme: MDCContainerScheming = MDCContainerScheme() { @@ -133,6 +134,7 @@ // MARK: Private Functions +@available(iOS 12, *) extension BottomNavigationControllerExampleViewController { fileprivate func apply(containerScheme: MDCContainerScheming) { navigationBar.applyPrimaryTheme(withScheme: containerScheme)
diff --git a/components/BottomNavigation/src/MDCBottomNavigationBar.h b/components/BottomNavigation/src/MDCBottomNavigationBar.h index c497c76..86ab3c4 100644 --- a/components/BottomNavigation/src/MDCBottomNavigationBar.h +++ b/components/BottomNavigation/src/MDCBottomNavigationBar.h
@@ -19,6 +19,7 @@ // migrated to no longer import MDCBottomNavigationBarDelegate as a transitive dependency. #import "MDCBottomNavigationBarDelegate.h" #import "MaterialElevation.h" +#import "MaterialShadow.h" #import "MaterialShadowElevations.h" @protocol MDCBottomNavigationBarDelegate; @@ -260,7 +261,7 @@ @end -#if MDC_AVAILABLE_SDK_IOS(13_0) +#if MDC_AVAILABLE_SDK_IOS(13_0) && !TARGET_OS_TV /** This component supports UIKit's Large Content Viewer. It is recommended that images associated with each tab bar item be backed with a PDF image with "preserve vector data" enabled within the assets @@ -276,6 +277,7 @@ For more details on the Large Content Viewer see: https://developer.apple.com/videos/play/wwdc2019/261/ */ +API_UNAVAILABLE(tvos, watchos) @interface MDCBottomNavigationBar (UILargeContentViewerInteractionDelegate) < UILargeContentViewerInteractionDelegate> @end
diff --git a/components/BottomNavigation/src/MDCBottomNavigationBar.m b/components/BottomNavigation/src/MDCBottomNavigationBar.m index 0a8548c..92c4a04 100644 --- a/components/BottomNavigation/src/MDCBottomNavigationBar.m +++ b/components/BottomNavigation/src/MDCBottomNavigationBar.m
@@ -26,6 +26,7 @@ #import "MDCBottomNavigationBarDelegate.h" #import "MaterialPalettes.h" #import "MaterialRipple.h" +#import "MaterialShadow.h" #import "MaterialShadowElevations.h" #import "MaterialShadowLayer.h" #import "MaterialTypography.h" @@ -72,8 +73,13 @@ @end @implementation MDCBottomNavigationBar + +static BOOL gEnablePerformantShadow = NO; + @synthesize mdc_overrideBaseElevation = _mdc_overrideBaseElevation; @synthesize mdc_elevationDidChangeBlock = _mdc_elevationDidChangeBlock; +@synthesize shadowsCollection = _shadowsCollection; +@synthesize elevation = _elevation; - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; @@ -117,13 +123,6 @@ } } - UIBlurEffect *defaultBlurEffect = [UIBlurEffect effectWithStyle:_backgroundBlurEffectStyle]; - _blurEffectView = [[UIVisualEffectView alloc] initWithEffect:defaultBlurEffect]; - _blurEffectView.hidden = !_backgroundBlurEnabled; - _blurEffectView.autoresizingMask = - (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - [self addSubview:_blurEffectView]; // Needs to always be at the bottom - _barView = [[UIView alloc] init]; _barView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin); @@ -141,11 +140,8 @@ [_barView addSubview:_itemsLayoutView]; _itemsLayoutView.accessibilityTraits = UIAccessibilityTraitTabBar; - _elevation = MDCShadowElevationBottomNavigationBar; - [(MDCShadowLayer *)self.layer setElevation:_elevation]; - UIColor *defaultShadowColor = UIColor.blackColor; - _shadowColor = defaultShadowColor; - self.layer.shadowColor = defaultShadowColor.CGColor; + self.elevation = MDCShadowElevationBottomNavigationBar; + self.shadowColor = gEnablePerformantShadow ? MDCShadowColor() : UIColor.blackColor; _itemViews = [NSMutableArray array]; _itemTitleFont = [UIFont mdc_standardFontForMaterialTextStyle:MDCFontTextStyleCaption]; @@ -165,7 +161,9 @@ [super layoutSubviews]; CGRect standardBounds = CGRectStandardize(self.bounds); - self.blurEffectView.frame = standardBounds; + if (self.blurEffectView) { + self.blurEffectView.frame = standardBounds; + } self.barView.frame = standardBounds; self.layer.shadowColor = self.shadowColor.CGColor; @@ -176,6 +174,10 @@ [self sizeItemsLayoutViewItemsDistributed:YES withBottomNavSize:size containerWidth:size.width]; } [self layoutItemViews]; + + if (gEnablePerformantShadow) { + [self updateShadow]; + } } - (void)safeAreaInsetsDidChange { @@ -210,16 +212,31 @@ } + (Class)layerClass { - return [MDCShadowLayer class]; + if (gEnablePerformantShadow) { + return [super layerClass]; + } else { + return [MDCShadowLayer class]; + } } - (void)setElevation:(MDCShadowElevation)elevation { - BOOL elevationChanged = !MDCCGFloatEqual(_elevation, elevation); - _elevation = elevation; - [(MDCShadowLayer *)self.layer setElevation:elevation]; - if (elevationChanged) { - [self mdc_elevationDidChange]; + if (MDCCGFloatEqual(_elevation, elevation)) { + return; } + _elevation = elevation; + if (gEnablePerformantShadow) { + [self updateShadow]; + } else { + MDCShadowLayer *shadowLayer = (MDCShadowLayer *)self.layer; + shadowLayer.elevation = elevation; + } + [self mdc_elevationDidChange]; +} + +- (void)updateShadow { + MDCConfigureShadowForView(self, + [self.shadowsCollection shadowForElevation:self.mdc_currentElevation], + self.shadowColor); } - (void)setShadowColor:(UIColor *)shadowColor { @@ -775,7 +792,9 @@ return; } _backgroundBlurEffectStyle = backgroundBlurEffectStyle; - self.blurEffectView.effect = [UIBlurEffect effectWithStyle:_backgroundBlurEffectStyle]; + if (self.blurEffectView) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:_backgroundBlurEffectStyle]; + } } - (void)setBackgroundBlurEnabled:(BOOL)backgroundBlurEnabled { @@ -784,7 +803,17 @@ } _backgroundBlurEnabled = backgroundBlurEnabled; - self.blurEffectView.hidden = !_backgroundBlurEnabled; + if (_backgroundBlurEnabled & !self.blurEffectView) { + UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:_backgroundBlurEffectStyle]; + self.blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + self.blurEffectView.hidden = !_backgroundBlurEnabled; + self.blurEffectView.autoresizingMask = + (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + [self insertSubview:self.blurEffectView atIndex:0]; // Needs to always be at the bottom + self.blurEffectView.frame = CGRectStandardize(self.bounds); + } else if (self.blurEffectView) { + self.blurEffectView.hidden = !_backgroundBlurEnabled; + } } - (void)setAlignment:(MDCBottomNavigationBarAlignment)alignment { @@ -836,6 +865,19 @@ return self.elevation; } +- (MDCShadowsCollection *)shadowsCollection { + if (!_shadowsCollection) { + _shadowsCollection = MDCShadowsCollectionDefault(); + } + return _shadowsCollection; +} + +- (void)setShadowsCollection:(MDCShadowsCollection *)shadowsCollection { + _shadowsCollection = shadowsCollection; + + [self updateShadow]; +} + - (void)cancelRippleInItemView:(MDCBottomNavigationItemView *)itemView animated:(BOOL)animated { if (self.enableRippleBehavior) { if (animated) { @@ -935,4 +977,14 @@ } #endif +#pragma mark - Performant Shadow Toggle + ++ (void)setEnablePerformantShadow:(BOOL)enable { + gEnablePerformantShadow = enable; +} + ++ (BOOL)enablePerformantShadow { + return gEnablePerformantShadow; +} + @end
diff --git a/components/BottomNavigation/src/PerformantShadowMigration/MDCBottomNavigationBar+ShadowsPrivate.h b/components/BottomNavigation/src/PerformantShadowMigration/MDCBottomNavigationBar+ShadowsPrivate.h new file mode 100644 index 0000000..5901ed1 --- /dev/null +++ b/components/BottomNavigation/src/PerformantShadowMigration/MDCBottomNavigationBar+ShadowsPrivate.h
@@ -0,0 +1,23 @@ +#import <UIKit/UIKit.h> + +#import "MDCBottomNavigationBar.h" + +/** + This category is temporary and is meant to allow us to A/B test the performance improvements of + using the new shadow vs the old shadow. When such test is finalized, we will delete this file and + the internal corresponding static property and move all clients to the new shadow. + TODO(b/185206035): Remove category for enabling performant shadow. + */ +@interface MDCBottomNavigationBar (ShadowsPrivate) + +/** + Returns a bool indicating if the performant shadow is turned on or not. + */ ++ (BOOL)enablePerformantShadow; + +/** + Enables/disables the performant shadow for the bottom navigation bar. + */ ++ (void)setEnablePerformantShadow:(BOOL)enable; + +@end
diff --git a/components/BottomNavigation/src/private/MDCBottomNavigationBar+Private.h b/components/BottomNavigation/src/private/MDCBottomNavigationBar+Private.h index 4a593d4..d21a361 100644 --- a/components/BottomNavigation/src/private/MDCBottomNavigationBar+Private.h +++ b/components/BottomNavigation/src/private/MDCBottomNavigationBar+Private.h
@@ -22,6 +22,16 @@ @interface MDCBottomNavigationBar () /** + A collection of MDCShadow instances each assigned an elevation (in dp). + + To create your own MDCShadowsCollection, please use the provided MDCShadowsCollectionBuilder and + populate it with MDCShadow instances using the provided MDCShadowBuilder. + + Defaults to MDCShadowsCollectionDefault(). + */ +@property(nonatomic, strong, null_resettable) MDCShadowsCollection *shadowsCollection; + +/** * Returns the tab bar item whose corresponding view contains the given point. * @param point CGPoint The point at which to get the corresponding tab bar item. The point must be * in the coordinate space of the receiver's bounds.
diff --git a/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m b/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m index 2d103b2..94aa859 100644 --- a/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m +++ b/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m
@@ -894,7 +894,12 @@ id<UILargeContentViewerItem> itemAfterReset = [self.bottomNavBar largeContentViewerInteraction:interaction itemAtPoint:CGPointZero]; - XCTAssertNil(itemAfterReset); + if (@available(iOS 13, *)) { + // TODO(b/184162265): Evaluate why this behavior is different on iOS 13+. + XCTAssertNotNil(itemAfterReset); + } else { + XCTAssertNil(itemAfterReset); + } } } #endif // MDC_AVAILABLE_SDK_IOS(13_0)
diff --git a/components/BottomNavigation/tests/unit/Theming/MDCBottomNavigationThemingTests.m b/components/BottomNavigation/tests/unit/MDCBottomNavigationThemingTests.m similarity index 99% rename from components/BottomNavigation/tests/unit/Theming/MDCBottomNavigationThemingTests.m rename to components/BottomNavigation/tests/unit/MDCBottomNavigationThemingTests.m index 9c8e5b2..8f1398a 100644 --- a/components/BottomNavigation/tests/unit/Theming/MDCBottomNavigationThemingTests.m +++ b/components/BottomNavigation/tests/unit/MDCBottomNavigationThemingTests.m
@@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#import "MaterialBottomNavigation.h" #import "MaterialBottomNavigation+Theming.h" #import <XCTest/XCTest.h>
diff --git a/components/BottomSheet/README.md b/components/BottomSheet/README.md index 05cb2a3..765023f 100644 --- a/components/BottomSheet/README.md +++ b/components/BottomSheet/README.md
@@ -68,20 +68,16 @@ We recommend giving all of these properties appropriate values for your use case. -## Types +**Types** There are three types suitable for different use cases: -1. [Standard bottom sheets](#standard-bottom-sheet) display content that complements the screen’s primary content and remain visible while users interact with the primary content +1. Standard bottom sheets display content that complements the screen’s primary content and remain visible while users interact with the primary content 1. [Modal bottom sheets](#modal-bottom-sheet) are an alternative to inline menus or simple dialogs on mobile and provide room for additional items, longer descriptions, and iconography, and must be dismissed in order to interact with the underlying content 1. [Expanding bottom sheets](#expanding-bottom-sheet) provide a small, collapsed surface that can be expanded by the user to access a key feature or task to offer the persistent access of a standard sheet with the space and focus of a modal sheet.  -## Standard bottom sheet - -Standard bottom sheets coexist with the screen’s main UI region and allow for simultaneously viewing and interacting with both regions. They are commonly used to keep a feature or secondary content visible on screen when content in main UI region is frequently scrolled or panned. - -There is no standard bottom sheet implementation on iOS. This is because the iOS bottom sheet implementation makes use of custom view controller transitions, which do not allow interaction with the presenting view controller, even when the presented view controller does not take up the whole screen. +_**Note:** Standard bottom sheets aren't supported on iOS. This is because the iOS bottom sheet implementation makes use of custom view controller transitions, which do not allow interaction with the presenting view controller, even when the presented view controller does not take up the whole screen._ ## Modal bottom sheet
diff --git a/components/BottomSheet/examples/BottomSheetKeyboardBehaviorExample.swift b/components/BottomSheet/examples/BottomSheetKeyboardBehaviorExample.swift new file mode 100644 index 0000000..b9737b0 --- /dev/null +++ b/components/BottomSheet/examples/BottomSheetKeyboardBehaviorExample.swift
@@ -0,0 +1,106 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 Foundation +import MaterialComponents.MaterialBottomSheet +import MaterialComponents.MaterialButtons +import MaterialComponents.MaterialButtons_Theming +import MaterialComponents.MaterialContainerScheme + +class BottomSheetKeyboardBehaviorExample: UIViewController { + + @objc var containerScheme = MDCContainerScheme() + var pushBottomSheetUpWhenKeyboardShows = true + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = containerScheme.colorScheme.backgroundColor + + let presentButton = MDCButton() + presentButton.setTitle("Show bottom sheet", for: .normal) + presentButton.applyContainedTheme(withScheme: containerScheme) + presentButton.addTarget( + self, + action: #selector(didTapPresentButton), + for: .touchUpInside) + + presentButton.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(presentButton) + + let toggleBehaviorButton = MDCButton() + toggleBehaviorButton.setTitle("Toggle keyboard behavior", for: .normal) + toggleBehaviorButton.applyContainedTheme(withScheme: containerScheme) + toggleBehaviorButton.addTarget( + self, + action: #selector(didTapToggleBehaviorButton), + for: .touchUpInside) + + toggleBehaviorButton.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(toggleBehaviorButton) + + NSLayoutConstraint.activate([ + presentButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), + presentButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor), + toggleBehaviorButton.centerXAnchor.constraint(equalTo: presentButton.centerXAnchor), + toggleBehaviorButton.bottomAnchor.constraint(equalTo: presentButton.topAnchor, constant: -20), + ]) + } + + @objc func didTapPresentButton(_ sender: MDCFloatingButton) { + let textFieldContent = BottomSheetWithUITextField() + let bottomSheet = MDCBottomSheetController(contentViewController: textFieldContent) + bottomSheet.ignoreKeyboardHeight = !pushBottomSheetUpWhenKeyboardShows + present(bottomSheet, animated: true) + } + + @objc func didTapToggleBehaviorButton(_ sender: MDCFloatingButton) { + pushBottomSheetUpWhenKeyboardShows = !pushBottomSheetUpWhenKeyboardShows + } + +} + +class BottomSheetWithUITextField: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + + let textField = UITextField() + textField.borderStyle = .roundedRect + textField.placeholder = "Type here" + textField.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(textField) + + NSLayoutConstraint.activate([ + textField.widthAnchor.constraint(equalToConstant: 200), + textField.heightAnchor.constraint(equalToConstant: 40), + textField.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), + textField.centerYAnchor.constraint(equalTo: self.view.centerYAnchor), + ]) + } +} + +// MARK: Catalog by convention +extension BottomSheetKeyboardBehaviorExample { + + @objc class func catalogMetadata() -> [String: Any] { + return [ + "breadcrumbs": ["Bottom Sheet", "Keyboard behavior"], + "primaryDemo": false, + "presentable": true, + ] + } +}
diff --git a/components/BottomSheet/src/MDCBottomSheetController.h b/components/BottomSheet/src/MDCBottomSheetController.h index e6b806c..1272430 100644 --- a/components/BottomSheet/src/MDCBottomSheetController.h +++ b/components/BottomSheet/src/MDCBottomSheetController.h
@@ -71,6 +71,14 @@ @property(nonatomic, assign) BOOL dismissOnDraggingDownSheet; /** + A Boolean value that controls whether the height of the keyboard should affect + the bottom sheet's frame when the keyboard shows on the screen. + + The default value is @c NO. + */ +@property(nonatomic) BOOL ignoreKeyboardHeight; + +/** The color applied to the sheet's background when presented by MDCBottomSheetPresentationController. Defaults to a semi-transparent Black.
diff --git a/components/BottomSheet/src/MDCBottomSheetController.m b/components/BottomSheet/src/MDCBottomSheetController.m index eb1e1c0..48679ca 100644 --- a/components/BottomSheet/src/MDCBottomSheetController.m +++ b/components/BottomSheet/src/MDCBottomSheetController.m
@@ -179,6 +179,15 @@ dismissOnDraggingDownSheet; } +- (BOOL)ignoreKeyboardHeight { + return _transitionController.ignoreKeyboardHeight; +} + +- (void)setIgnoreKeyboardHeight:(BOOL)ignoreKeyboardHeight { + _transitionController.ignoreKeyboardHeight = ignoreKeyboardHeight; + self.mdc_bottomSheetPresentationController.ignoreKeyboardHeight = ignoreKeyboardHeight; +} + - (void)bottomSheetWillChangeState:(MDCBottomSheetPresentationController *)bottomSheet sheetState:(MDCSheetState)sheetState { _state = sheetState;
diff --git a/components/BottomSheet/src/MDCBottomSheetPresentationController.h b/components/BottomSheet/src/MDCBottomSheetPresentationController.h index 90a2fec..8889a42 100644 --- a/components/BottomSheet/src/MDCBottomSheetPresentationController.h +++ b/components/BottomSheet/src/MDCBottomSheetPresentationController.h
@@ -46,6 +46,14 @@ @property(nonatomic, assign) BOOL simulateScrollViewBounce; /** + A Boolean value that controls whether the height of the keyboard should affect + the bottom sheet's frame when the keyboard shows on the screen. + + The default value is @c NO. + */ +@property(nonatomic) BOOL ignoreKeyboardHeight; + +/** When set to false, the bottom sheet controller can't be dismissed by tapping outside of sheet area. */ @property(nonatomic, assign) BOOL dismissOnBackgroundTap;
diff --git a/components/BottomSheet/src/MDCBottomSheetPresentationController.m b/components/BottomSheet/src/MDCBottomSheetPresentationController.m index c30e3a4..5cf2a71 100644 --- a/components/BottomSheet/src/MDCBottomSheetPresentationController.m +++ b/components/BottomSheet/src/MDCBottomSheetPresentationController.m
@@ -75,6 +75,7 @@ if (self) { _adjustHeightForSafeAreaInsets = YES; _simulateScrollViewBounce = YES; + _ignoreKeyboardHeight = NO; } return self; } @@ -139,6 +140,7 @@ self.sheetView.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.sheetView.dismissOnDraggingDownSheet = self.dismissOnDraggingDownSheet; self.sheetView.adjustHeightForSafeAreaInsets = self.adjustHeightForSafeAreaInsets; + self.sheetView.ignoreKeyboardHeight = self.ignoreKeyboardHeight; [containerView addSubview:_dimmingView]; [containerView addSubview:self.sheetView]; @@ -321,6 +323,13 @@ } } +- (void)setIgnoreKeyboardHeight:(BOOL)ignoreKeyboardHeight { + _ignoreKeyboardHeight = ignoreKeyboardHeight; + if (_sheetView) { + _sheetView.ignoreKeyboardHeight = ignoreKeyboardHeight; + } +} + - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection];
diff --git a/components/BottomSheet/src/MDCBottomSheetTransitionController.h b/components/BottomSheet/src/MDCBottomSheetTransitionController.h index c2d7210..8323029 100644 --- a/components/BottomSheet/src/MDCBottomSheetTransitionController.h +++ b/components/BottomSheet/src/MDCBottomSheetTransitionController.h
@@ -73,6 +73,14 @@ */ @property(nonatomic, assign) BOOL adjustHeightForSafeAreaInsets; +/** + A Boolean value that controls whether the height of the keyboard should affect + the bottom sheet's frame when the keyboard shows on the screen. + + The default value is @c NO. + */ +@property(nonatomic) BOOL ignoreKeyboardHeight; + @end @interface MDCBottomSheetTransitionController (ScrimAccessibility)
diff --git a/components/BottomSheet/src/MDCBottomSheetTransitionController.m b/components/BottomSheet/src/MDCBottomSheetTransitionController.m index 5e1eef3..5418761 100644 --- a/components/BottomSheet/src/MDCBottomSheetTransitionController.m +++ b/components/BottomSheet/src/MDCBottomSheetTransitionController.m
@@ -64,6 +64,7 @@ presentationController.scrimAccessibilityLabel = _scrimAccessibilityLabel; presentationController.preferredSheetHeight = _preferredSheetHeight; presentationController.adjustHeightForSafeAreaInsets = _adjustHeightForSafeAreaInsets; + presentationController.ignoreKeyboardHeight = _ignoreKeyboardHeight; _currentPresentationController = presentationController; return presentationController; } @@ -177,6 +178,11 @@ _currentPresentationController.adjustHeightForSafeAreaInsets = adjustHeightForSafeAreaInsets; } +- (void)setIgnoreKeyboardHeight:(BOOL)ignoreKeyboardHeight { + _ignoreKeyboardHeight = ignoreKeyboardHeight; + _currentPresentationController.ignoreKeyboardHeight = ignoreKeyboardHeight; +} + - (void)setIsScrimAccessibilityElement:(BOOL)isScrimAccessibilityElement { _isScrimAccessibilityElement = isScrimAccessibilityElement; _currentPresentationController.isScrimAccessibilityElement = isScrimAccessibilityElement;
diff --git a/components/BottomSheet/src/private/MDCSheetContainerView.h b/components/BottomSheet/src/private/MDCSheetContainerView.h index 220466b..9faef89 100644 --- a/components/BottomSheet/src/private/MDCSheetContainerView.h +++ b/components/BottomSheet/src/private/MDCSheetContainerView.h
@@ -32,6 +32,14 @@ @property(nonatomic) BOOL willBeDismissed; /** + A Boolean value that controls whether the height of the keyboard should affect + the bottom sheet's frame when the keyboard shows on the screen. + + The default value is @c NO. + */ +@property(nonatomic) BOOL ignoreKeyboardHeight; + +/** When set to false, the bottom sheet controller can't be dismissed by dragging the sheet down. */ @property(nonatomic, assign) BOOL dismissOnDraggingDownSheet;
diff --git a/components/BottomSheet/src/private/MDCSheetContainerView.m b/components/BottomSheet/src/private/MDCSheetContainerView.m index 21188b0..f4d59d8 100644 --- a/components/BottomSheet/src/private/MDCSheetContainerView.m +++ b/components/BottomSheet/src/private/MDCSheetContainerView.m
@@ -64,6 +64,7 @@ self = [super initWithFrame:frame]; if (self) { _willBeDismissed = NO; + _ignoreKeyboardHeight = NO; _simulateScrollViewBounce = simulateScrollViewBounce; if (UIAccessibilityIsVoiceOverRunning()) { _sheetState = MDCSheetStateExtended; @@ -167,10 +168,6 @@ } [self updateSheetFrame]; - // Adjusts the pane to the correct snap point, e.g. after a rotation. - if (self.window) { - [self animatePaneWithInitialVelocity:CGPointZero]; - } } - (void)safeAreaInsetsDidChange { @@ -187,6 +184,10 @@ CGRect scrollViewFrame = CGRectStandardize(self.sheet.scrollView.frame); scrollViewFrame.size = CGSizeMake(scrollViewFrame.size.width, CGRectGetHeight(self.frame)); self.sheet.scrollView.frame = scrollViewFrame; + + // Note this is needed to make sure the full displayed frame updates to reflect the new safe + // area insets after rotation. See b/183357841 for context. + [self updateSheetFrame]; } } @@ -239,11 +240,6 @@ _preferredSheetHeight = adjustedPreferredSheetHeight; [self updateSheetFrame]; - - // Adjusts the pane to the correct snap point if we are visible. - if (self.window) { - [self animatePaneWithInitialVelocity:CGPointZero]; - } } - (void)setPreferredSheetHeight:(CGFloat)preferredSheetHeight { @@ -274,6 +270,11 @@ contentFrame.size.height = [self effectiveSheetHeight]; } self.contentView.frame = contentFrame; + + // Adjusts the pane to the correct snap point, e.g. after a rotation. + if (self.window) { + [self animatePaneWithInitialVelocity:CGPointZero]; + } } - (void)updateSheetState { @@ -339,9 +340,12 @@ // Calculates the snap-point for the view to spring to. - (CGPoint)targetPoint { CGRect bounds = self.bounds; - CGFloat keyboardOffset = [MDCKeyboardWatcher sharedKeyboardWatcher].visibleKeyboardHeight; CGFloat midX = CGRectGetMidX(bounds); - CGFloat bottomY = CGRectGetMaxY(bounds) - keyboardOffset; + CGFloat bottomY = CGRectGetMaxY(bounds); + if (!self.ignoreKeyboardHeight) { + CGFloat keyboardOffset = [MDCKeyboardWatcher sharedKeyboardWatcher].visibleKeyboardHeight; + bottomY -= keyboardOffset; + } CGPoint targetPoint; switch (self.sheetState) {
diff --git a/components/ButtonBar/tests/snapshot/MDCButtonBarSnapshotTests.m b/components/ButtonBar/tests/snapshot/MDCButtonBarSnapshotTests.m index 5693c07..1fb3c7c 100644 --- a/components/ButtonBar/tests/snapshot/MDCButtonBarSnapshotTests.m +++ b/components/ButtonBar/tests/snapshot/MDCButtonBarSnapshotTests.m
@@ -322,7 +322,7 @@ - (void)testLayoutPositionTrailingWithTitlesLTR { // When - self.buttonBar.layoutPosition = MDCFloatingButtonImageLocationTrailing; + self.buttonBar.layoutPosition = MDCButtonBarLayoutPositionTrailing; CGSize fitSize = [self.buttonBar sizeThatFits:CGSizeZero]; self.buttonBar.bounds = CGRectMake(0, 0, fitSize.width * 2, fitSize.height); @@ -335,7 +335,7 @@ [self changeItemsToImages]; // When - self.buttonBar.layoutPosition = MDCFloatingButtonImageLocationTrailing; + self.buttonBar.layoutPosition = MDCButtonBarLayoutPositionTrailing; CGSize fitSize = [self.buttonBar sizeThatFits:CGSizeZero]; self.buttonBar.bounds = CGRectMake(0, 0, fitSize.width * 2, fitSize.height); @@ -345,7 +345,7 @@ - (void)testLayoutPositionTrailingWithTitlesRTL { // When - self.buttonBar.layoutPosition = MDCFloatingButtonImageLocationTrailing; + self.buttonBar.layoutPosition = MDCButtonBarLayoutPositionTrailing; [self changeToRTLAndArabic]; CGSize fitSize = [self.buttonBar sizeThatFits:CGSizeZero]; self.buttonBar.bounds = CGRectMake(0, 0, fitSize.width * 2, fitSize.height); @@ -359,7 +359,7 @@ [self changeItemsToImages]; // When - self.buttonBar.layoutPosition = MDCFloatingButtonImageLocationTrailing; + self.buttonBar.layoutPosition = MDCButtonBarLayoutPositionTrailing; [self changeToRTLAndArabic]; CGSize fitSize = [self.buttonBar sizeThatFits:CGSizeZero]; self.buttonBar.bounds = CGRectMake(0, 0, fitSize.width * 2, fitSize.height);
diff --git a/components/Buttons/docs/buttons.md b/components/Buttons/docs/buttons.md index 7c65002..ad0e193 100644 --- a/components/Buttons/docs/buttons.md +++ b/components/Buttons/docs/buttons.md
@@ -160,9 +160,9 @@ (representing a day of the week) has the `accessibilityHint` value, "Toggles this day." -## Types +**Types** -There are four types of buttons: 1. [Text button](#text-button) 2. [Outlined button](#outlined-button) 3. [Contained button](#contained-button) 4. Toggle button (*not supported in iOS*)" +There are four types of buttons: 1\. [Text button](#text-button) 2\. [Outlined button](#outlined-button) 3\. [Contained button](#contained-button) 4\. Toggle button (*not supported in iOS*)" 
diff --git a/components/Buttons/docs/fabs.md b/components/Buttons/docs/fabs.md index 7829a0f..66bf253 100644 --- a/components/Buttons/docs/fabs.md +++ b/components/Buttons/docs/fabs.md
@@ -140,7 +140,7 @@ (representing a day of the week) has the `accessibilityHint` value, "Toggles this day." -## Types +**Types** There are three types of FABs: 1\. [Regular FABs](#regular-fab) 2\. [Mini FABs](#mini-fab) 3\. [Extended FABs](#extended-fab)
diff --git a/components/Buttons/examples/supplemental/ButtonsTypicalUseSupplemental.m b/components/Buttons/examples/supplemental/ButtonsTypicalUseSupplemental.m index a9d1567..6e27dd4 100644 --- a/components/Buttons/examples/supplemental/ButtonsTypicalUseSupplemental.m +++ b/components/Buttons/examples/supplemental/ButtonsTypicalUseSupplemental.m
@@ -35,6 +35,7 @@ @"\nA floating action button (FAB) represents the primary action of a screen.", @"primaryDemo" : @YES, @"presentable" : @YES, + @"thresholdPercentage" : @1.5, }; } @@ -47,6 +48,7 @@ @"breadcrumbs" : @[ @"Buttons", @"Shaped Buttons" ], @"primaryDemo" : @NO, @"presentable" : @YES, + @"thresholdPercentage" : @1.5, }; } @@ -122,6 +124,14 @@ CGFloat labelOffset = (CGRectGetHeight(button.bounds) - CGRectGetHeight(label.bounds)) / 2; label.center = CGPointMake(centerX - (CGRectGetWidth(label.bounds) / 2) - kViewOffsetToCenter, heightSum + labelOffset + (CGRectGetHeight(label.bounds) / 2)); + + // Pin the label's frame to pixel boundaries to reduce snapshot flakiness due to inaccuracies in + // floating point rounding behavior on the GPU when taking snapshots. + CGRect labelFrame = label.frame; + labelFrame.origin.x = floor(labelFrame.origin.x); + labelFrame.origin.y = floor(labelFrame.origin.y); + label.frame = labelFrame; + heightSum += CGRectGetHeight(button.bounds); if (i < self.buttons.count - 1) { heightSum += button.enabled ? 24 : 36;
diff --git a/components/Buttons/src/MDCButton.h b/components/Buttons/src/MDCButton.h index a65428b..2440c27 100644 --- a/components/Buttons/src/MDCButton.h +++ b/components/Buttons/src/MDCButton.h
@@ -18,6 +18,7 @@ #import "MaterialElevation.h" #import "MaterialInk.h" #import "MaterialRipple.h" +#import "MaterialShadow.h" #import "MaterialShadowElevations.h" #import "MaterialShapes.h"
diff --git a/components/Buttons/src/MDCButton.m b/components/Buttons/src/MDCButton.m index 15a3553..6bee2b3 100644 --- a/components/Buttons/src/MDCButton.m +++ b/components/Buttons/src/MDCButton.m
@@ -18,6 +18,7 @@ #import "MaterialElevation.h" #import "MaterialInk.h" #import "MaterialRipple.h" +#import "MaterialShadow.h" #import "MaterialShadowElevations.h" #import "MaterialShapeLibrary.h" #import "MaterialShapes.h" @@ -112,6 +113,9 @@ BOOL _mdc_adjustsFontForContentSizeCategory; BOOL _cornerRadiusObserverAdded; CGFloat _inkMaxRippleRadius; + + MDCShapeMediator *_shapedLayer; + CGFloat _currentElevation; } @property(nonatomic, strong, readonly, nonnull) MDCStatefulRippleView *rippleView; #pragma clang diagnostic push @@ -130,14 +134,21 @@ @implementation MDCButton +static BOOL gEnablePerformantShadow = NO; + @synthesize mdc_overrideBaseElevation = _mdc_overrideBaseElevation; @synthesize mdc_elevationDidChangeBlock = _mdc_elevationDidChangeBlock; @synthesize visibleAreaInsets = _visibleAreaInsets; @synthesize visibleAreaLayoutGuide = _visibleAreaLayoutGuide; +@synthesize shadowsCollection = _shadowsCollection; @dynamic layer; + (Class)layerClass { - return [MDCShapedShadowLayer class]; + if (gEnablePerformantShadow) { + return [super class]; + } else { + return [MDCShapedShadowLayer class]; + } } - (instancetype)init { @@ -170,7 +181,9 @@ // Storyboards will set the backgroundColor via the UIView backgroundColor setter, so we have // to write that in to our _backgroundColors dictionary. - _backgroundColors[@(UIControlStateNormal)] = self.layer.shapedBackgroundColor; + _backgroundColors[@(UIControlStateNormal)] = gEnablePerformantShadow + ? _shapedLayer.shapedBackgroundColor + : self.layer.shapedBackgroundColor; [self updateBackgroundColor]; } return self; @@ -179,6 +192,9 @@ - (void)commonMDCButtonInit { // TODO(b/142861610): Default to `NO`, then remove once all internal usage is migrated. _enableTitleFontForState = YES; + if (gEnablePerformantShadow) { + _shapedLayer = [[MDCShapeMediator alloc] initWithViewLayer:self.layer]; + } _disabledAlpha = MDCButtonDisabledAlpha; _enabledAlpha = self.alpha; _uppercaseTitle = YES; @@ -191,6 +207,7 @@ _accessibilityTraitsIncludesButton = YES; _adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = YES; _mdc_overrideBaseElevation = -1; + _currentElevation = 0; if (!_backgroundColors) { // _backgroundColors may have already been initialized by setting the backgroundColor setter. @@ -206,11 +223,12 @@ #endif self.layer.cornerRadius = MDCButtonDefaultCornerRadius; - if (!self.layer.shapeGenerator) { - self.layer.shadowPath = [self boundingPath].CGPath; + if (gEnablePerformantShadow) { + self.layer.shadowColor = MDCShadowColor().CGColor; + } else { + self.layer.shadowColor = [UIColor blackColor].CGColor; + self.layer.elevation = [self elevationForState:self.state]; } - self.layer.shadowColor = [UIColor blackColor].CGColor; - self.layer.elevation = [self elevationForState:self.state]; _shadowColors = [NSMutableDictionary dictionary]; _shadowColors[@(UIControlStateNormal)] = [UIColor colorWithCGColor:self.layer.shadowColor]; @@ -336,8 +354,15 @@ } } - if (!self.layer.shapeGenerator) { - self.layer.shadowPath = [self boundingPath].CGPath; + if (gEnablePerformantShadow) { + if (_shapedLayer.shapeGenerator) { + [_shapedLayer layoutShapedSublayers]; + } + [self updateShadow]; + } else { + if (!self.layer.shapeGenerator) { + self.layer.shadowPath = [self boundingPath].CGPath; + } } // Center unbounded ink view frame taking into account possible insets using contentRectForBounds. @@ -732,12 +757,17 @@ - (void)animateButtonToHeightForState:(UIControlState)state { CGFloat newElevation = [self elevationForState:state]; - if (MDCCGFloatEqual(self.layer.elevation, newElevation)) { + if (MDCCGFloatEqual(self.mdc_currentElevation, newElevation)) { return; } + _currentElevation = newElevation; [CATransaction begin]; [CATransaction setAnimationDuration:MDCButtonAnimationDuration]; - self.layer.elevation = newElevation; + if (gEnablePerformantShadow) { + [self updateShadow]; + } else { + self.layer.elevation = newElevation; + } [CATransaction commit]; [self mdc_elevationDidChange]; } @@ -754,7 +784,8 @@ } - (UIColor *)backgroundColor { - return self.layer.shapedBackgroundColor; + return gEnablePerformantShadow ? _shapedLayer.shapedBackgroundColor + : self.layer.shapedBackgroundColor; } - (UIColor *)backgroundColorForState:(UIControlState)state { @@ -818,10 +849,15 @@ _userElevations[@(state)] = @(elevation); MDCShadowElevation newElevation = [self elevationForState:self.state]; // If no change to the current elevation, don't perform updates - if (MDCCGFloatEqual(newElevation, self.layer.elevation)) { + if (MDCCGFloatEqual(newElevation, self.mdc_currentElevation)) { return; } - self.layer.elevation = newElevation; + _currentElevation = newElevation; + if (gEnablePerformantShadow) { + [self updateShadow]; + } else { + self.layer.elevation = newElevation; + } [self mdc_elevationDidChange]; // The elevation of the normal state controls whether this button is flat or not, and flat buttons @@ -832,6 +868,18 @@ } } +- (void)updateShadow { + if (_shapedLayer.shapeGenerator == nil) { + MDCConfigureShadowForView(self, + [self.shadowsCollection shadowForElevation:self.mdc_currentElevation], + [self shadowColorForState:self.state] ?: MDCShadowColor()); + } else { + MDCConfigureShadowForViewWithPath( + self, [self.shadowsCollection shadowForElevation:self.mdc_currentElevation], + [self shadowColorForState:self.state] ?: MDCShadowColor(), self.layer.shadowPath); + } +} + #pragma mark - Border Color - (UIColor *)borderColorForState:(UIControlState)state { @@ -891,7 +939,11 @@ // We fall back to UIControlStateNormal if there is no value for the current state. width = _borderWidths[@(UIControlStateNormal)]; } - self.layer.shapedBorderWidth = (width != nil) ? (CGFloat)width.doubleValue : 0; + if (gEnablePerformantShadow) { + _shapedLayer.shapedBorderWidth = (width != nil) ? (CGFloat)width.doubleValue : 0; + } else { + self.layer.shapedBorderWidth = (width != nil) ? (CGFloat)width.doubleValue : 0; + } } #pragma mark - Title Font @@ -942,7 +994,14 @@ #pragma mark - MaterialElevation - (CGFloat)mdc_currentElevation { - return [self elevationForState:self.state]; + return _currentElevation; +} + +- (MDCShadowsCollection *)shadowsCollection { + if (!_shadowsCollection) { + _shadowsCollection = MDCShadowsCollectionDefault(); + } + return _shadowsCollection; } #pragma mark - Private methods @@ -1025,7 +1084,11 @@ - (void)updateBackgroundColor { // When shapeGenerator is unset then self.layer.shapedBackgroundColor sets the layer's // backgroundColor. Whereas when shapeGenerator is set the sublayer's fillColor is set. - self.layer.shapedBackgroundColor = [self backgroundColorForState:self.state]; + if (gEnablePerformantShadow) { + _shapedLayer.shapedBackgroundColor = [self backgroundColorForState:self.state]; + } else { + self.layer.shapedBackgroundColor = [self backgroundColorForState:self.state]; + } [self updateDisabledTitleColor]; } @@ -1060,7 +1123,11 @@ // We fall back to UIControlStateNormal if there is no value for the current state. color = _borderColors[@(UIControlStateNormal)]; } - self.layer.shapedBorderColor = color ?: NULL; + if (gEnablePerformantShadow) { + _shapedLayer.shapedBorderColor = color ?: NULL; + } else { + self.layer.shapedBorderColor = color ?: NULL; + } } - (void)updateTitleFont { @@ -1088,29 +1155,53 @@ if (shapeGenerator) { self.layer.shadowPath = nil; } else { - self.layer.shadowPath = [self boundingPath].CGPath; + if (gEnablePerformantShadow) { + MDCConfigureShadowForView( + self, [self.shadowsCollection shadowForElevation:self.mdc_currentElevation], + [self shadowColorForState:self.state] ?: MDCShadowColor()); + } else { + self.layer.shadowPath = [self boundingPath].CGPath; + } } - self.layer.shapeGenerator = shapeGenerator; + + if (gEnablePerformantShadow) { + _shapedLayer.shapeGenerator = shapeGenerator; + } else { + self.layer.shapeGenerator = shapeGenerator; + } // The imageView is added very early in the lifecycle of a UIButton, therefore we need to move // the colorLayer behind the imageView otherwise the image will not show. // Because the inkView needs to go below the imageView, but above the colorLayer // we need to have the colorLayer be at the back - [self.layer.colorLayer removeFromSuperlayer]; - if (self.enableRippleBehavior) { - [self.layer insertSublayer:self.layer.colorLayer below:self.rippleView.layer]; + if (gEnablePerformantShadow) { + [_shapedLayer.colorLayer removeFromSuperlayer]; + if (self.enableRippleBehavior) { + [self.layer insertSublayer:_shapedLayer.colorLayer below:self.rippleView.layer]; + } else { + [self.layer insertSublayer:_shapedLayer.colorLayer below:self.inkView.layer]; + } } else { - [self.layer insertSublayer:self.layer.colorLayer below:self.inkView.layer]; + [self.layer.colorLayer removeFromSuperlayer]; + if (self.enableRippleBehavior) { + [self.layer insertSublayer:self.layer.colorLayer below:self.rippleView.layer]; + } else { + [self.layer insertSublayer:self.layer.colorLayer below:self.inkView.layer]; + } } [self updateBackgroundColor]; [self updateInkForShape]; } - (id<MDCShapeGenerating>)shapeGenerator { + if (gEnablePerformantShadow) { + return _shapedLayer.shapeGenerator; + } return self.layer.shapeGenerator; } - (void)updateInkForShape { - CGRect boundingBox = CGPathGetBoundingBox(self.layer.shapeLayer.path); + CGRect boundingBox = CGPathGetBoundingBox(gEnablePerformantShadow ? _shapedLayer.shapeLayer.path + : self.layer.shapeLayer.path); self.inkView.maxRippleRadius = (CGFloat)(hypot(CGRectGetHeight(boundingBox), CGRectGetWidth(boundingBox)) / 2 + 10); self.inkView.layer.masksToBounds = NO; @@ -1348,4 +1439,14 @@ } } +#pragma mark - Performant Shadow Toggle + ++ (void)setEnablePerformantShadow:(BOOL)enable { + gEnablePerformantShadow = enable; +} + ++ (BOOL)enablePerformantShadow { + return gEnablePerformantShadow; +} + @end
diff --git a/components/Buttons/src/PerformantShadowMigration/MDCButton+ShadowsPrivate.h b/components/Buttons/src/PerformantShadowMigration/MDCButton+ShadowsPrivate.h new file mode 100644 index 0000000..d62ecb8 --- /dev/null +++ b/components/Buttons/src/PerformantShadowMigration/MDCButton+ShadowsPrivate.h
@@ -0,0 +1,23 @@ +#import <UIKit/UIKit.h> + +#import "MDCButton.h" + +/** + This category is temporary and is meant to allow us to A/B test the performance improvements of + using the new shadow vs the old shadow. When such test is finalized, we will delete this file and + the internal corresponding static property and move all clients to the new shadow. + TODO(b/185206035): Remove category for enabling performant shadow. + */ +@interface MDCButton (ShadowsPrivate) + +/** + Returns a bool indicating if the performant shadow is turned on or not. + */ ++ (BOOL)enablePerformantShadow; + +/** + Enables/disables the performant shadow for the button. + */ ++ (void)setEnablePerformantShadow:(BOOL)enable; + +@end
diff --git a/components/Buttons/src/private/MDCButton+Subclassing.h b/components/Buttons/src/private/MDCButton+Subclassing.h index 20e97a4..ebd3789 100644 --- a/components/Buttons/src/private/MDCButton+Subclassing.h +++ b/components/Buttons/src/private/MDCButton+Subclassing.h
@@ -41,3 +41,17 @@ - (nonnull UIBezierPath *)boundingPath; @end + +@interface MDCButton () + +/** + A collection of MDCShadow instances each assigned an elevation (in dp). + + To create your own MDCShadowsCollection, please use the provided MDCShadowsCollectionBuilder and + populate it with MDCShadow instances using the provided MDCShadowBuilder. + + Defaults to MDCShadowsCollectionDefault(). + */ +@property(nonatomic, strong, null_resettable) MDCShadowsCollection *shadowsCollection; + +@end
diff --git a/components/Buttons/tests/snapshot/ButtonCustomTraitCollectionSnapshotTests.m b/components/Buttons/tests/snapshot/ButtonCustomTraitCollectionSnapshotTests.m index ba6c0a2..98869cf 100644 --- a/components/Buttons/tests/snapshot/ButtonCustomTraitCollectionSnapshotTests.m +++ b/components/Buttons/tests/snapshot/ButtonCustomTraitCollectionSnapshotTests.m
@@ -19,8 +19,8 @@ #import "MaterialAvailability.h" #import "MaterialButtons.h" -#import "MaterialColor.h" #import "MaterialTypography.h" +#import "MaterialColor.h" /** A @c MDCButton test fake to override the @c traitCollection to test for dynamic type. */ @interface ButtonDynamicTypeSnapshotTestFakeButton : MDCButton @@ -77,15 +77,10 @@ /** Used to set the @c UIContentSizeCategory on an @c MDCButton. - - @note On iOS 9 or below this method has no impact. */ - (void)setButtonTraitCollectionSizeToSize:(UIContentSizeCategory)sizeCategory { - UITraitCollection *traitCollection = [[UITraitCollection alloc] init]; - if (@available(iOS 10.0, *)) { - traitCollection = - [UITraitCollection traitCollectionWithPreferredContentSizeCategory:sizeCategory]; - } + UITraitCollection *traitCollection = + [UITraitCollection traitCollectionWithPreferredContentSizeCategory:sizeCategory]; self.button.traitCollectionOverride = traitCollection; }
diff --git a/components/Buttons/tests/snapshot/ButtonsFlippedImageRenderingSnapshotTests.m b/components/Buttons/tests/snapshot/ButtonsFlippedImageRenderingSnapshotTests.m index 675996b..202e221 100644 --- a/components/Buttons/tests/snapshot/ButtonsFlippedImageRenderingSnapshotTests.m +++ b/components/Buttons/tests/snapshot/ButtonsFlippedImageRenderingSnapshotTests.m
@@ -46,16 +46,11 @@ // before a horizontally flipped UIImage causes the image to render outside of the UIImageView's // frame. - (void)testHorizontallyFlippedImageWithContentInsets { - // Given - if (@available(iOS 10.0, *)) { - // When - self.button.contentEdgeInsets = UIEdgeInsetsMake(10, 20, 10, 20); - UIImage *testImage = - [[UIImage mdc_testImageOfSize:CGSizeMake(24, 24)] imageWithHorizontallyFlippedOrientation]; - [self.button setImage:testImage forState:UIControlStateNormal]; - } else { - // Fallback on earlier versions - } + // When + self.button.contentEdgeInsets = UIEdgeInsetsMake(10, 20, 10, 20); + UIImage *testImage = + [[UIImage mdc_testImageOfSize:CGSizeMake(24, 24)] imageWithHorizontallyFlippedOrientation]; + [self.button setImage:testImage forState:UIControlStateNormal]; // Then [self.button sizeToFit];
diff --git a/components/Buttons/tests/unit/supplemental/ButtonTestView.h b/components/Buttons/tests/unit/ButtonTestView.h similarity index 100% rename from components/Buttons/tests/unit/supplemental/ButtonTestView.h rename to components/Buttons/tests/unit/ButtonTestView.h
diff --git a/components/Buttons/tests/unit/supplemental/ButtonTestView.m b/components/Buttons/tests/unit/ButtonTestView.m similarity index 100% rename from components/Buttons/tests/unit/supplemental/ButtonTestView.m rename to components/Buttons/tests/unit/ButtonTestView.m
diff --git a/components/Buttons/tests/unit/Theming/ButtonsThemingTest.swift b/components/Buttons/tests/unit/ButtonsThemingTest.swift similarity index 100% rename from components/Buttons/tests/unit/Theming/ButtonsThemingTest.swift rename to components/Buttons/tests/unit/ButtonsThemingTest.swift
diff --git a/components/Buttons/tests/unit/MDCButtonInterfaceBuilderCompatibilityTests.m b/components/Buttons/tests/unit/MDCButtonInterfaceBuilderCompatibilityTests.m index 5aa3a29..9b60eb7 100644 --- a/components/Buttons/tests/unit/MDCButtonInterfaceBuilderCompatibilityTests.m +++ b/components/Buttons/tests/unit/MDCButtonInterfaceBuilderCompatibilityTests.m
@@ -15,8 +15,8 @@ #import <Foundation/Foundation.h> #import <XCTest/XCTest.h> -#import "supplemental/ButtonTestView.h" #import "MaterialButtons.h" +#import "ButtonTestView.h" @interface MDCButtonInterfaceBuilderCompatibilityTests : XCTestCase
diff --git a/components/Cards/examples/CardsCollectionExample.m b/components/Cards/examples/CardsCollectionExample.m index 979e6b4..322e61b 100644 --- a/components/Cards/examples/CardsCollectionExample.m +++ b/components/Cards/examples/CardsCollectionExample.m
@@ -33,16 +33,13 @@ defaultLayout.minimumInteritemSpacing = 0; defaultLayout.minimumLineSpacing = 1; defaultLayout.scrollDirection = UICollectionViewScrollDirectionVertical; - self = [super initWithCollectionViewLayout:defaultLayout]; - if (self) { - self.containerScheme = [[MDCContainerScheme alloc] init]; - } - return self; + return [self initWithCollectionViewLayout:defaultLayout]; } - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout { self = [super initWithCollectionViewLayout:layout]; if (self) { + self.containerScheme = [[MDCContainerScheme alloc] init]; _collectionViewLayout = layout; } return self; @@ -131,8 +128,6 @@ @"breadcrumbs" : @[ @"Cards", @"Collection Card Cells" ], @"primaryDemo" : @NO, @"presentable" : @NO, - @"skip_snapshots" : @YES, // Crashing with 'NSInternalInconsistencyException', reason: 'layout - // cannot be nil in setCollectionViewLayout:' }; }
diff --git a/components/Cards/examples/CardsCollectionTintingExample.m b/components/Cards/examples/CardsCollectionTintingExample.m index 7cd310b..4f418a3 100644 --- a/components/Cards/examples/CardsCollectionTintingExample.m +++ b/components/Cards/examples/CardsCollectionTintingExample.m
@@ -32,16 +32,13 @@ defaultLayout.minimumInteritemSpacing = 0; defaultLayout.minimumLineSpacing = 1; defaultLayout.scrollDirection = UICollectionViewScrollDirectionVertical; - self = [super initWithCollectionViewLayout:defaultLayout]; - if (self) { - self.containerScheme = [[MDCContainerScheme alloc] init]; - } - return self; + return [self initWithCollectionViewLayout:defaultLayout]; } - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout { self = [super initWithCollectionViewLayout:layout]; if (self) { + self.containerScheme = [[MDCContainerScheme alloc] init]; _collectionViewLayout = layout; } return self; @@ -116,8 +113,6 @@ @"breadcrumbs" : @[ @"Cards", @"Collection Card Tinting" ], @"primaryDemo" : @NO, @"presentable" : @NO, - @"skip_snapshots" : @YES, // Crashing with 'NSInternalInconsistencyException', reason: 'layout - // cannot be nil in setCollectionViewLayout:' }; }
diff --git a/components/Cards/tests/unit/Theming/CardsMaterialThemingTests.swift b/components/Cards/tests/unit/CardsMaterialThemingTests.swift similarity index 100% rename from components/Cards/tests/unit/Theming/CardsMaterialThemingTests.swift rename to components/Cards/tests/unit/CardsMaterialThemingTests.swift
diff --git a/components/Checkboxes/.jazzy.yaml b/components/Checkboxes/.jazzy.yaml deleted file mode 100644 index dc223e9..0000000 --- a/components/Checkboxes/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: Checkboxes -umbrella_header: src/MaterialCheckboxes.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/Checkboxes/README.md b/components/Checkboxes/README.md deleted file mode 100644 index f2e6f8d..0000000 --- a/components/Checkboxes/README.md +++ /dev/null
@@ -1,3 +0,0 @@ -# Checkboxes - -The [Checkboxes component](https://material.io/go/design-checkboxes) will not be implemented on iOS. Please [use the native UISwitch to align with cross-platform guidance](https://material.io/design/platform-guidance/cross-platform-adaptation.html).
diff --git a/components/Chips/README.md b/components/Chips/README.md index 25ffa22..78709e6 100644 --- a/components/Chips/README.md +++ b/components/Chips/README.md
@@ -67,14 +67,9 @@ Remember to set any relevant `accessibilityLabels` or `accessibilityTraits`, especially if you are not satisfied with default system-assigned values. -## Types +**Types** -There are four types of chips: - -1. [Input (text entry)](#input-chip) -1. [Choice](#choice-chip) -1. [Filter](#filter-chip) -1. [Action](#action-chip) +There are four types of chips: 1\. [Input (text entry)](#input-chip) 2\. [Choice](#choice-chip) 3\. [Filter](#filter-chip) 4\. [Action](#action-chip)  @@ -92,7 +87,6 @@ ``` #### Objective-C - ```objc MDCChipView *chipView = [[MDCChipView alloc] init]; chipView.titleLabel.text = @"Tap me"; @@ -156,6 +150,18 @@ We currently provide an implementation of Input Chips called `MDCChipField`. +<!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +let chipField = MDCChipField() +chipField.delegate = self +chipField.textField.placeholderLabel.text = "This is a chip field." +chipField.showChipsDeleteButton = true +chipField.sizeToFit() +view.addSubview(chipField) +``` + +#### Objective-C ```objc MDCChipField *chipField = [[MDCChipField alloc] init]; chipField.delegate = self; @@ -176,6 +182,13 @@ - Use `MDCChipCollectionViewFlowLayout` as the `UICollectionView` layout: <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +let layout = MDCChipCollectionViewFlowLayout() +collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) +``` + +#### Objective-C ```objc MDCChipCollectionViewFlowLayout *layout = [[MDCChipCollectionViewFlowLayout alloc] init]; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; @@ -183,26 +196,46 @@ <!--</div>--> - Leave the default `UICollectionView` selection setting (single selection). - - Use `MDCChipCollectionViewCell` as `UICollectionView` cells. (`MDCChipCollectionViewCell` manages the state of the chip based on selection state of `UICollectionView` automatically) <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +func loadView() { + super.loadView() + + collectionView.register( + MDCChipCollectionViewCell.self, + forCellWithReuseIdentifier: "identifier") +} + +func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath +) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "identifier", for: indexPath) as! MDCChipCollectionViewCell + let chipView = cell.chipView + // configure the chipView to be a choice chip + return cell +} +``` + +#### Objective-C ```objc - (void)loadView { [super loadView]; - … + [_collectionView registerClass:[MDCChipCollectionViewCell class] forCellWithReuseIdentifier:@"identifier"]; - ... - } +} - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { MDCChipCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"identifier" forIndexPath:indexPath]; MDCChipView *chipView = cell.chipView; - // configure the chipView - return cell; + // configure the chipView to be a choice chip + return cell; } ``` <!--</div>--> @@ -222,6 +255,13 @@ - Use `MDCChipCollectionViewFlowLayout` as the `UICollectionView` layout: <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +let layout = MDCChipCollectionViewFlowLayout() +collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) +``` + +#### Objective-C ```objc MDCChipCollectionViewFlowLayout *layout = [[MDCChipCollectionViewFlowLayout alloc] init]; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; @@ -231,30 +271,57 @@ - Allow multi cell selection in the `UICollectionView`: <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +collectionView.allowsMultipleSelection = true +``` + +#### Objective-C ```objc -collectionView.allowsMultipleSelection = YES; +collectionView.allowsMultipleSelection = YES; ``` <!--</div>--> - Use `MDCChipCollectionViewCell` as `UICollectionView` cells. (`MDCChipCollectionViewCell` manages the state of the chip based on selection state of `UICollectionView` automatically) <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +func loadView() { + super.loadView() + + collectionView.register( + MDCChipCollectionViewCell.self, + forCellWithReuseIdentifier: "identifier") +} + +func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath +) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "identifier", for: indexPath) as! MDCChipCollectionViewCell + let chipView = cell.chipView + // configure the chipView to be a filter chip + return cell +} +``` + +#### Objective-C ```objc - (void)loadView { [super loadView]; - … + [_collectionView registerClass:[MDCChipCollectionViewCell class] forCellWithReuseIdentifier:@"identifier"]; - ... - } +} - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { MDCChipCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"identifier" forIndexPath:indexPath]; MDCChipView *chipView = cell.chipView; - // configure the chipView - return cell; + // configure the chipView to be a filter chip + return cell; } ``` <!--</div>--> @@ -274,6 +341,13 @@ - Use `MDCChipCollectionViewFlowLayout` as the `UICollectionView` layout: <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +let layout = MDCChipCollectionViewFlowLayout() +collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) +``` + +#### Objective-C ```objc MDCChipCollectionViewFlowLayout *layout = [[MDCChipCollectionViewFlowLayout alloc] init]; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; @@ -284,22 +358,43 @@ - Use `MDCChipCollectionViewCell` as `UICollectionView` cells. (`MDCChipCollectionViewCell` manages the state of the chip based on selection state of `UICollectionView` automatically) <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +func loadView() { + super.loadView() + + collectionView.register( + MDCChipCollectionViewCell.self, + forCellWithReuseIdentifier: "identifier") +} + +func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath +) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "identifier", for: indexPath) as! MDCChipCollectionViewCell + let chipView = cell.chipView + // configure the chipView to be an action chip + return cell +} +``` + +#### Objective-C ```objc - (void)loadView { [super loadView]; - … + [_collectionView registerClass:[MDCChipCollectionViewCell class] forCellWithReuseIdentifier:@"identifier"]; - ... - } +} - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { MDCChipCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"identifier" forIndexPath:indexPath]; MDCChipView *chipView = cell.chipView; - // configure the chipView - return cell; + // configure the chipView to be an action chip + return cell; } ``` <!--</div>--> @@ -307,6 +402,18 @@ - Make sure that `MDCChipCollectionViewCell` does not stay in selected state <!--<div class="material-code-render" markdown="1">--> +#### Swift +```swift +func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + // For action chips, we never want the chip to stay in selected state. + // Other possible apporaches would be relying on theming or Customizing collectionViewCell + // selected state. + collectionView.deselectItem(at: indexPath, animated: false) + // Trigger the action +} +``` + +#### Objective-C ```objc - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { // For action chips, we never want the chip to stay in selected state.
diff --git a/components/Chips/src/MDCChipField.m b/components/Chips/src/MDCChipField.m index e2485b4..7f46803 100644 --- a/components/Chips/src/MDCChipField.m +++ b/components/Chips/src/MDCChipField.m
@@ -18,6 +18,7 @@ #import <MDFInternationalization/MDFInternationalization.h> #import "MDCChipFieldDelegate.h" +#import "MDCChipViewDeleteButton.h" #import "MaterialTextFields.h" NSString *const MDCEmptyTextString = @""; @@ -28,8 +29,6 @@ static const CGFloat MDCChipFieldIndent = 4; static const CGFloat MDCChipFieldHorizontalMargin = 8; static const CGFloat MDCChipFieldVerticalMargin = 8; -static const CGFloat MDCChipFieldClearButtonSquareWidthHeight = 24; -static const CGFloat MDCChipFieldClearImageSquareWidthHeight = 18; static const UIKeyboardType MDCChipFieldDefaultKeyboardType = UIKeyboardTypeEmailAddress; const CGFloat MDCChipFieldDefaultMinTextFieldWidth = 44; @@ -377,147 +376,13 @@ } - (void)addClearButtonToChip:(MDCChipView *)chip { - UIControl *clearButton = [[UIControl alloc] init]; - CGFloat clearButtonWidthAndHeight = MDCChipFieldClearButtonSquareWidthHeight; - clearButton.frame = CGRectMake(0, 0, clearButtonWidthAndHeight, clearButtonWidthAndHeight); - clearButton.layer.cornerRadius = clearButtonWidthAndHeight / 2; - UIImageView *clearImageView = [[UIImageView alloc] initWithImage:[self drawClearButton]]; - CGFloat widthAndHeight = MDCChipFieldClearImageSquareWidthHeight; - CGFloat padding = - (MDCChipFieldClearButtonSquareWidthHeight - MDCChipFieldClearImageSquareWidthHeight) / 2; - clearImageView.frame = CGRectMake(padding, padding, widthAndHeight, widthAndHeight); - clearButton.tintColor = [UIColor.blackColor colorWithAlphaComponent:(CGFloat)0.6]; - [clearButton addSubview:clearImageView]; + MDCChipViewDeleteButton *clearButton = [[MDCChipViewDeleteButton alloc] init]; chip.accessoryView = clearButton; [clearButton addTarget:self action:@selector(deleteChip:) forControlEvents:UIControlEventTouchUpInside]; } -- (UIImage *)drawClearButton { - CGSize clearButtonSize = - CGSizeMake(MDCChipFieldClearImageSquareWidthHeight, MDCChipFieldClearImageSquareWidthHeight); - - CGRect bounds = CGRectMake(0, 0, clearButtonSize.width, clearButtonSize.height); - UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0); - [UIColor.grayColor setFill]; - [MDCPathForClearButtonImageFrame(bounds) fill]; - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - return image; -} - -static inline UIBezierPath *MDCPathForClearButtonImageFrame(CGRect frame) { - // GENERATED CODE - - CGRect innerBounds = - CGRectMake(CGRectGetMinX(frame) + 2, CGRectGetMinY(frame) + 2, - floor((frame.size.width - 2) * (CGFloat)0.90909 + (CGFloat)0.5), - floor((frame.size.height - 2) * (CGFloat)0.90909 + (CGFloat)0.5)); - UIBezierPath *ic_clear_path = [UIBezierPath bezierPath]; - [ic_clear_path moveToPoint:CGPointMake(CGRectGetMinX(innerBounds) + - (CGFloat)0.50000 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height)]; - [ic_clear_path - addCurveToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + 1 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.50000 * innerBounds.size.height) - controlPoint1:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.77600 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height) - controlPoint2:CGPointMake( - CGRectGetMinX(innerBounds) + 1 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.22400 * innerBounds.size.height)]; - [ic_clear_path - addCurveToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.50000 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 1 * innerBounds.size.height) - controlPoint1:CGPointMake( - CGRectGetMinX(innerBounds) + 1 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.77600 * innerBounds.size.height) - controlPoint2:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.77600 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 1 * innerBounds.size.height)]; - [ic_clear_path - addCurveToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + 0 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.50000 * innerBounds.size.height) - controlPoint1:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.22400 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 1 * innerBounds.size.height) - controlPoint2:CGPointMake( - CGRectGetMinX(innerBounds) + 0 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.77600 * innerBounds.size.height)]; - [ic_clear_path - addCurveToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.50000 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height) - controlPoint1:CGPointMake( - CGRectGetMinX(innerBounds) + 0 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.22400 * innerBounds.size.height) - controlPoint2:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.22400 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height)]; - [ic_clear_path closePath]; - [ic_clear_path - moveToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.73417 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.31467 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.68700 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.26750 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.50083 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.45367 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.31467 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.26750 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.26750 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.31467 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.45367 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.50083 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.26750 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.68700 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.31467 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.73417 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.50083 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.54800 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.68700 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.73417 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.73417 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.68700 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.54800 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.50083 * innerBounds.size.height)]; - [ic_clear_path - addLineToPoint:CGPointMake( - CGRectGetMinX(innerBounds) + (CGFloat)0.73417 * innerBounds.size.width, - CGRectGetMinY(innerBounds) + (CGFloat)0.31467 * innerBounds.size.height)]; - [ic_clear_path closePath]; - - return ic_clear_path; -} - - (void)deleteChip:(id)sender { UIControl *deleteButton = (UIControl *)sender; MDCChipView *chip = (MDCChipView *)deleteButton.superview; @@ -557,18 +422,27 @@ if ([self.delegate respondsToSelector:@selector(chipFieldShouldBeginEditing:)]) { shouldBeginEditing = [self.delegate chipFieldShouldBeginEditing:self]; } - if (shouldBeginEditing) { - if (textField == self.textField) { - [self deselectAllChips]; - } - if ([self.delegate respondsToSelector:@selector(chipFieldDidBeginEditing:)]) { - [self.delegate chipFieldDidBeginEditing:self]; - } - } return shouldBeginEditing; } - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { + BOOL shouldEndEditing = YES; + if ([self.delegate respondsToSelector:@selector(chipFieldShouldEndEditing:)]) { + shouldEndEditing = [self.delegate chipFieldShouldEndEditing:self]; + } + return shouldEndEditing; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + if (textField == self.textField) { + [self deselectAllChips]; + } + if ([self.delegate respondsToSelector:@selector(chipFieldDidBeginEditing:)]) { + [self.delegate chipFieldDidBeginEditing:self]; + } +} + +- (void)textFieldDidEndEditing:(UITextField *)textField { if ((self.delimiter & MDCChipFieldDelimiterDidEndEditing) == MDCChipFieldDelimiterDidEndEditing) { if (textField == self.textField) { [self commitInput]; @@ -577,7 +451,6 @@ if ([self.delegate respondsToSelector:@selector(chipFieldDidEndEditing:)]) { [self.delegate chipFieldDidEndEditing:self]; } - return YES; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { @@ -754,7 +627,7 @@ context:nil]; return MAX(placeholderDesiredWidth, CGRectGetWidth(desiredRect) + MDCChipFieldHorizontalMargin + self.contentEdgeInsets.right + - MDCChipFieldClearImageSquareWidthHeight); + [MDCChipViewDeleteButton imageSideLength]); } - (CGFloat)placeholderDesiredWidth {
diff --git a/components/Chips/src/MDCChipFieldDelegate.h b/components/Chips/src/MDCChipFieldDelegate.h index b232ce6..d253f38 100644 --- a/components/Chips/src/MDCChipFieldDelegate.h +++ b/components/Chips/src/MDCChipFieldDelegate.h
@@ -24,6 +24,13 @@ - (BOOL)chipFieldShouldBeginEditing:(nonnull MDCChipField *)chipField; /** + Asks the delegate if editing should end in the specified chip field. + + @param chipField The @c MDCChipField where is about to end. + */ +- (BOOL)chipFieldShouldEndEditing:(nonnull MDCChipField *)chipField; + +/** Tells the delegate that editing began in the specified chip field. @param chipField The MDCChipField where editing began.
diff --git a/components/Shadow/src/private/MDCShadow+Internal.h b/components/Chips/src/MDCChipViewDeleteButton.h similarity index 68% rename from components/Shadow/src/private/MDCShadow+Internal.h rename to components/Chips/src/MDCChipViewDeleteButton.h index 8c7225d..455ae71 100644 --- a/components/Shadow/src/private/MDCShadow+Internal.h +++ b/components/Chips/src/MDCChipViewDeleteButton.h
@@ -14,12 +14,15 @@ #import <UIKit/UIKit.h> -#import "MDCShadow.h" +/* + A Material chip delete button. This is used by @c MDCChipField, but can also be used in any @c + MDCChipView by setting it as its @c accessoryView. + */ +@interface MDCChipViewDeleteButton : UIButton -@interface MDCShadow () - -- (instancetype)initWithOpacity:(CGFloat)opacity - radius:(CGFloat)radius - offset:(CGSize)offset NS_DESIGNATED_INITIALIZER; +/* + The length of the sides of the image view that displays the circular X. + */ ++ (CGFloat)imageSideLength; @end
diff --git a/components/Chips/src/MDCChipViewDeleteButton.m b/components/Chips/src/MDCChipViewDeleteButton.m new file mode 100644 index 0000000..6506e31 --- /dev/null +++ b/components/Chips/src/MDCChipViewDeleteButton.m
@@ -0,0 +1,196 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 <CoreGraphics/CoreGraphics.h> + +#import "MDCChipViewDeleteButton.h" + +static const CGFloat MDCChipFieldClearButtonSquareWidthHeight = 24.0f; +static const CGFloat MDCChipFieldClearImageSquareWidthHeight = 18.0f; + +@implementation MDCChipViewDeleteButton + +- (instancetype)init { + CGFloat clearButtonWidthAndHeight = MDCChipFieldClearButtonSquareWidthHeight; + CGRect frame = CGRectMake(0, 0, clearButtonWidthAndHeight, clearButtonWidthAndHeight); + return [self initWithFrame:frame]; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self commonMDCChipViewDeleteButtonInit]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + [self commonMDCChipViewDeleteButtonInit]; + } + return self; +} + +- (CGSize)sizeThatFits:(CGSize)size { + return CGSizeMake(MDCChipFieldClearButtonSquareWidthHeight, + MDCChipFieldClearButtonSquareWidthHeight); +} + +- (CGSize)intrinsicContentSize { + return CGSizeMake(MDCChipFieldClearButtonSquareWidthHeight, + MDCChipFieldClearButtonSquareWidthHeight); +} + +- (void)commonMDCChipViewDeleteButtonInit { + CGFloat clearButtonWidthAndHeight = MDCChipFieldClearButtonSquareWidthHeight; + self.frame = CGRectMake(0, 0, clearButtonWidthAndHeight, clearButtonWidthAndHeight); + self.layer.cornerRadius = clearButtonWidthAndHeight / 2; + UIImageView *clearImageView = [[UIImageView alloc] initWithImage:[self drawClearButton]]; + CGFloat widthAndHeight = MDCChipFieldClearImageSquareWidthHeight; + CGFloat padding = + (MDCChipFieldClearButtonSquareWidthHeight - MDCChipFieldClearImageSquareWidthHeight) / 2; + clearImageView.frame = CGRectMake(padding, padding, widthAndHeight, widthAndHeight); + self.tintColor = [UIColor.blackColor colorWithAlphaComponent:(CGFloat)0.6]; + [self addSubview:clearImageView]; +} + +- (UIImage *)drawClearButton { + CGSize clearButtonSize = + CGSizeMake(MDCChipFieldClearImageSquareWidthHeight, MDCChipFieldClearImageSquareWidthHeight); + + CGRect bounds = CGRectMake(0, 0, clearButtonSize.width, clearButtonSize.height); + UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0); + [UIColor.grayColor setFill]; + [MDCPathForClearButtonImageFrame(bounds) fill]; + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + return image; +} + +static inline UIBezierPath *MDCPathForClearButtonImageFrame(CGRect frame) { + // This code was generated very long ago and then copied over from MDCChipField . + + CGRect innerBounds = CGRectMake(CGRectGetMinX(frame) + 2, CGRectGetMinY(frame) + 2, + floor((frame.size.width - 2) * (CGFloat)0.90909 + (CGFloat)0.5), + floor((frame.size.height - 2) * (CGFloat)0.90909 + (CGFloat)0.5)); + UIBezierPath *ic_clear_path = [UIBezierPath bezierPath]; + [ic_clear_path moveToPoint:CGPointMake(CGRectGetMinX(innerBounds) + + (CGFloat)0.50000 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height)]; + [ic_clear_path + addCurveToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + 1 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.50000 * innerBounds.size.height) + controlPoint1:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.77600 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height) + controlPoint2:CGPointMake( + CGRectGetMinX(innerBounds) + 1 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.22400 * innerBounds.size.height)]; + [ic_clear_path + addCurveToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.50000 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 1 * innerBounds.size.height) + controlPoint1:CGPointMake( + CGRectGetMinX(innerBounds) + 1 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.77600 * innerBounds.size.height) + controlPoint2:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.77600 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 1 * innerBounds.size.height)]; + [ic_clear_path + addCurveToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + 0 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.50000 * innerBounds.size.height) + controlPoint1:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.22400 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 1 * innerBounds.size.height) + controlPoint2:CGPointMake( + CGRectGetMinX(innerBounds) + 0 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.77600 * innerBounds.size.height)]; + [ic_clear_path + addCurveToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.50000 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height) + controlPoint1:CGPointMake( + CGRectGetMinX(innerBounds) + 0 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.22400 * innerBounds.size.height) + controlPoint2:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.22400 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + 0 * innerBounds.size.height)]; + [ic_clear_path closePath]; + [ic_clear_path + moveToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.73417 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.31467 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.68700 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.26750 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.50083 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.45367 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.31467 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.26750 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.26750 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.31467 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.45367 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.50083 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.26750 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.68700 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.31467 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.73417 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.50083 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.54800 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.68700 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.73417 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.73417 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.68700 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.54800 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.50083 * innerBounds.size.height)]; + [ic_clear_path + addLineToPoint:CGPointMake( + CGRectGetMinX(innerBounds) + (CGFloat)0.73417 * innerBounds.size.width, + CGRectGetMinY(innerBounds) + (CGFloat)0.31467 * innerBounds.size.height)]; + [ic_clear_path closePath]; + + return ic_clear_path; +} + ++ (CGFloat)imageSideLength { + return MDCChipFieldClearImageSquareWidthHeight; +} + +@end
diff --git a/components/Chips/src/MaterialChips.h b/components/Chips/src/MaterialChips.h index 2fef783..acd6c2f 100644 --- a/components/Chips/src/MaterialChips.h +++ b/components/Chips/src/MaterialChips.h
@@ -17,3 +17,4 @@ #import "MDCChipField.h" #import "MDCChipFieldDelegate.h" #import "MDCChipView.h" +#import "MDCChipViewDeleteButton.h"
diff --git a/components/Chips/tests/snapshot/MDCChipViewLayoutSnapshotTests.m b/components/Chips/tests/snapshot/MDCChipViewLayoutSnapshotTests.m index 2031f17..f174719 100644 --- a/components/Chips/tests/snapshot/MDCChipViewLayoutSnapshotTests.m +++ b/components/Chips/tests/snapshot/MDCChipViewLayoutSnapshotTests.m
@@ -90,10 +90,8 @@ } - (void)changeToRTL:(MDCChipViewLayoutCustomTraitCollectionFake *)chip { - if (@available(iOS 10.0, *)) { - chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; } #pragma mark - ContentPadding
diff --git a/components/Chips/tests/snapshot/MDCChipViewSnapshotTests.m b/components/Chips/tests/snapshot/MDCChipViewSnapshotTests.m index ebc6308..743fbd0 100644 --- a/components/Chips/tests/snapshot/MDCChipViewSnapshotTests.m +++ b/components/Chips/tests/snapshot/MDCChipViewSnapshotTests.m
@@ -138,10 +138,8 @@ - (void)testBaselineThemedChipWithImageRTL { // Given - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.imageView.image = [self leadingImage]; @@ -162,10 +160,8 @@ - (void)testOutlinedThemedChipWithImageRTL { // Given - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.imageView.image = [self leadingImage]; @@ -199,10 +195,8 @@ - (void)testDefaultChipWithAccessoryViewAndPositiveTopLeftAccessoryPaddingRTL { // Given self.chip.accessoryView = [self deleteButton]; - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.accessoryPadding = UIEdgeInsetsMake(10, 10, 0, 0); @@ -225,10 +219,8 @@ - (void)testDefaultChipWithAccessoryViewAndPositiveBottomRightAccessoryPaddingRTL { // Given self.chip.accessoryView = [self deleteButton]; - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.accessoryPadding = UIEdgeInsetsMake(0, 0, 10, 10); @@ -251,10 +243,8 @@ - (void)testDefaultChipWithAccessoryViewAndNegativeTopLeftAccessoryPaddingRTL { // Given self.chip.accessoryView = [self deleteButton]; - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.accessoryPadding = UIEdgeInsetsMake(-6, -6, 0, 0); @@ -277,10 +267,8 @@ - (void)testDefaultChipWithAccessoryViewAndNegativeBottomRightAccessoryPaddingRTL { // Given self.chip.accessoryView = [self deleteButton]; - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.accessoryPadding = UIEdgeInsetsMake(0, 0, -6, -6); @@ -300,10 +288,8 @@ - (void)testBaselineThemedChipWithAccessoryViewRTL { // Given - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.accessoryView = [self deleteButton]; @@ -324,10 +310,8 @@ - (void)testOutlinedThemedChipWithAccessoryViewRTL { // Given - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.accessoryView = [self deleteButton]; @@ -360,10 +344,8 @@ - (void)testBaselineThemedChipWithImageAndAccessoryViewRTL { // Given - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.imageView.image = [self leadingImage]; @@ -386,10 +368,8 @@ - (void)testOutlinedThemedChipWithImageAndAccessoryViewRTL { // Given - if (@available(iOS 10.0, *)) { - self.chip.traitCollectionOverride = [UITraitCollection - traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; - } + self.chip.traitCollectionOverride = [UITraitCollection + traitCollectionWithLayoutDirection:UITraitEnvironmentLayoutDirectionRightToLeft]; // When self.chip.imageView.image = [self leadingImage];
diff --git a/components/Chips/tests/unit/ChipsDelegateTests.m b/components/Chips/tests/unit/ChipsDelegateTests.m index e3e2b55..4e48104 100644 --- a/components/Chips/tests/unit/ChipsDelegateTests.m +++ b/components/Chips/tests/unit/ChipsDelegateTests.m
@@ -24,7 +24,9 @@ @property(nonatomic, nullable) MDCChipField *chip; @property(nonatomic, copy, nullable) NSString *delegateTextInput; @property(nonatomic) BOOL delegateShouldBeginEditing; +@property(nonatomic) BOOL delegateShouldEndEditing; @property(nonatomic) BOOL delegateDidBeginEditingCalled; +@property(nonatomic) BOOL delegateDidEndEditingCalled; @end @@ -36,6 +38,7 @@ self.chip = [[MDCChipField alloc] init]; self.chip.delegate = self; self.delegateShouldBeginEditing = YES; + self.delegateShouldEndEditing = YES; } - (void)tearDown { @@ -43,7 +46,9 @@ self.chip.delegate = nil; self.chip = nil; self.delegateShouldBeginEditing = YES; + self.delegateShouldEndEditing = YES; self.delegateDidBeginEditingCalled = NO; + self.delegateDidEndEditingCalled = NO; [super tearDown]; } @@ -68,7 +73,7 @@ XCTAssertEqual((unsigned long)self.delegateTextInput.length, 0UL); } -- (void)testDelegateShouldNotBeginEditingDoesNotTriggerDidBeginEditing { +- (void)testDelegateShouldNotBeginEditing { // Given self.delegateShouldBeginEditing = NO; @@ -78,10 +83,9 @@ // Then XCTAssertFalse(shouldBeginEditing); - XCTAssertFalse(self.delegateDidBeginEditingCalled); } -- (void)testShouldBeginEditingTriggersDidBeginEditing { +- (void)testShouldBeginEditing { // Given self.delegateShouldBeginEditing = YES; @@ -91,9 +95,48 @@ // Then XCTAssertTrue(shouldBeginEditing); +} + +- (void)testTextFieldDidBeginEditingTriggersDidBeginEditing { + // When + [self.chip.textField.delegate textFieldDidBeginEditing:self.chip.textField]; + + // Then XCTAssertTrue(self.delegateDidBeginEditingCalled); } +- (void)testDelegateShouldNotEndEditing { + // Given + self.delegateShouldEndEditing = NO; + + // When + BOOL shouldEndEditing = + [self.chip.textField.delegate textFieldShouldEndEditing:self.chip.textField]; + + // Then + XCTAssertFalse(shouldEndEditing); +} + +- (void)testDelegateShouldEndEditing { + // Given + self.delegateShouldEndEditing = YES; + + // When + BOOL shouldEndEditing = + [self.chip.textField.delegate textFieldShouldEndEditing:self.chip.textField]; + + // Then + XCTAssertTrue(shouldEndEditing); +} + +- (void)testTextFieldDidEndEditingTriggersDidEndEditing { + // When + [self.chip.textField.delegate textFieldDidEndEditing:self.chip.textField]; + + // Then + XCTAssertTrue(self.delegateDidEndEditingCalled); +} + #pragma mark - MDCChipFieldDelegate - (void)chipField:(nonnull MDCChipField *)chipField didChangeInput:(nullable NSString *)input { @@ -108,4 +151,12 @@ self.delegateDidBeginEditingCalled = YES; } +- (BOOL)chipFieldShouldEndEditing:(MDCChipField *)chipField { + return self.delegateShouldEndEditing; +} + +- (void)chipFieldDidEndEditing:(MDCChipField *)chipField { + self.delegateDidEndEditingCalled = YES; +} + @end
diff --git a/components/Chips/tests/unit/Theming/ChipsMaterialThemingTests.swift b/components/Chips/tests/unit/ChipsMaterialThemingTests.swift similarity index 100% rename from components/Chips/tests/unit/Theming/ChipsMaterialThemingTests.swift rename to components/Chips/tests/unit/ChipsMaterialThemingTests.swift
diff --git a/components/Chips/tests/unit/ChipsTests.m b/components/Chips/tests/unit/ChipsTests.m index 199646a..7aa4598 100644 --- a/components/Chips/tests/unit/ChipsTests.m +++ b/components/Chips/tests/unit/ChipsTests.m
@@ -412,32 +412,30 @@ } - (void)testChipViewDynamicTypeBehavior { - if (@available(iOS 10.0, *)) { - // Given - MDCChipsTestsFakeChipView *chipView = [[MDCChipsTestsFakeChipView alloc] init]; - chipView.mdc_adjustsFontForContentSizeCategory = YES; - chipView.adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = NO; - UIFont *titleFont = [UIFont systemFontOfSize:14.0 weight:UIFontWeightMedium]; - MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleBody2]; - titleFont = [fontScaler scaledFontWithFont:titleFont]; - titleFont = [titleFont mdc_scaledFontAtDefaultSize]; - chipView.titleFont = titleFont; - chipView.titleLabel.text = @"Chip"; - CGFloat originalFontSize = chipView.titleLabel.font.pointSize; + // Given + MDCChipsTestsFakeChipView *chipView = [[MDCChipsTestsFakeChipView alloc] init]; + chipView.mdc_adjustsFontForContentSizeCategory = YES; + chipView.adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = NO; + UIFont *titleFont = [UIFont systemFontOfSize:14.0 weight:UIFontWeightMedium]; + MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleBody2]; + titleFont = [fontScaler scaledFontWithFont:titleFont]; + titleFont = [titleFont mdc_scaledFontAtDefaultSize]; + chipView.titleFont = titleFont; + chipView.titleLabel.text = @"Chip"; + CGFloat originalFontSize = chipView.titleLabel.font.pointSize; - // When - UIContentSizeCategory size = UIContentSizeCategoryExtraExtraLarge; - UITraitCollection *traitCollection = - [UITraitCollection traitCollectionWithPreferredContentSizeCategory:size]; - chipView.traitCollectionOverride = traitCollection; - [NSNotificationCenter.defaultCenter - postNotificationName:UIContentSizeCategoryDidChangeNotification - object:nil]; + // When + UIContentSizeCategory size = UIContentSizeCategoryExtraExtraLarge; + UITraitCollection *traitCollection = + [UITraitCollection traitCollectionWithPreferredContentSizeCategory:size]; + chipView.traitCollectionOverride = traitCollection; + [NSNotificationCenter.defaultCenter + postNotificationName:UIContentSizeCategoryDidChangeNotification + object:nil]; - // Then - CGFloat actualFontSize = chipView.titleLabel.font.pointSize; - XCTAssertGreaterThan(actualFontSize, originalFontSize); - } + // Then + CGFloat actualFontSize = chipView.titleLabel.font.pointSize; + XCTAssertGreaterThan(actualFontSize, originalFontSize); } - (void)testChipViewAdjustsFontForContentSizeCategoryWhenScaledFontIsUnavailableDefaultValue {
diff --git a/components/DataTables/.jazzy.yaml b/components/DataTables/.jazzy.yaml deleted file mode 100644 index 50d7d6c..0000000 --- a/components/DataTables/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: DataTables -umbrella_header: src/MaterialDataTables.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/DataTables/README.md b/components/DataTables/README.md deleted file mode 100644 index f6072e9..0000000 --- a/components/DataTables/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -# Data Tables - -The [Data Tables component](https://material.io/go/design-data-tables) is yet to be completed, please follow the [tracking issue](https://www.pivotaltracker.com/epic/show/3950581) for more information. -
diff --git a/components/Dialogs/src/MDCAlertController.h b/components/Dialogs/src/MDCAlertController.h index 571fa6b..b8ba096 100644 --- a/components/Dialogs/src/MDCAlertController.h +++ b/components/Dialogs/src/MDCAlertController.h
@@ -400,14 +400,18 @@ Defaults to UIKit's supportedInterfaceOrientations. */ -@property(nonatomic) UIInterfaceOrientationMask supportedInterfaceOrientationsOverride; +@property(nonatomic) + UIInterfaceOrientationMask supportedInterfaceOrientationsOverride API_UNAVAILABLE(tvos, watchos) + ; /** The interface orientation to use when presenting the alert. Defaults to UIKit's preferredInterfaceOrientationForPresentation. */ -@property(nonatomic) UIInterfaceOrientation preferredInterfaceOrientationForPresentationOverride; +@property(nonatomic) + UIInterfaceOrientation preferredInterfaceOrientationForPresentationOverride API_UNAVAILABLE( + tvos, watchos); /** The transition style to use when presenting the view controller override.
diff --git a/components/Dialogs/src/MDCAlertController.m b/components/Dialogs/src/MDCAlertController.m index 1488bb7..480e5fd 100644 --- a/components/Dialogs/src/MDCAlertController.m +++ b/components/Dialogs/src/MDCAlertController.m
@@ -866,7 +866,15 @@ MDCDialogPresentationController *dialogPresentationController = self.mdc_dialogPresentationController; if (dialogPresentationController.dismissOnBackgroundTap) { - [self.presentingViewController dismissViewControllerAnimated:YES completion:NULL]; + void (^dismissalCompletion)(void) = ^{ + if ([dialogPresentationController.dialogPresentationControllerDelegate + respondsToSelector:@selector(dialogPresentationControllerDidDismiss:)]) { + [dialogPresentationController.dialogPresentationControllerDelegate + dialogPresentationControllerDidDismiss:dialogPresentationController]; + } + }; + [self.presentingViewController dismissViewControllerAnimated:YES + completion:dismissalCompletion]; return YES; } return NO;
diff --git a/components/Dialogs/src/private/MDCAlertActionManager.m b/components/Dialogs/src/private/MDCAlertActionManager.m index ff774a5..8827176 100644 --- a/components/Dialogs/src/private/MDCAlertActionManager.m +++ b/components/Dialogs/src/private/MDCAlertActionManager.m
@@ -32,8 +32,9 @@ self = [super init]; if (self) { _actions = [[NSMutableArray alloc] init]; - _actionButtons = [NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory - valueOptions:NSMapTableStrongMemory]; + _actionButtons = [NSMapTable + mapTableWithKeyOptions:(NSMapTableObjectPointerPersonality | NSMapTableWeakMemory) + valueOptions:NSMapTableStrongMemory]; } return self; } @@ -95,7 +96,7 @@ button.accessibilityIdentifier = action.accessibilityIdentifier; #ifdef __IPHONE_13_4 if (@available(iOS 13.4, *)) { - if ([self respondsToSelector:@selector(isPointerInteractionEnabled)]) { + if ([button respondsToSelector:@selector(setPointerInteractionEnabled:)]) { button.pointerInteractionEnabled = YES; } }
diff --git a/components/Dialogs/src/private/MDCAlertControllerView+Private.m b/components/Dialogs/src/private/MDCAlertControllerView+Private.m index d780fb1..4d2fbb7 100644 --- a/components/Dialogs/src/private/MDCAlertControllerView+Private.m +++ b/components/Dialogs/src/private/MDCAlertControllerView+Private.m
@@ -36,6 +36,35 @@ static const CGFloat MDCDialogMessageOpacity = 0.54f; +/** Calculates the minimum text height for a single line text using device metrics. */ +static CGFloat SingleLineTextViewHeight(NSString *_Nullable title, UIFont *_Nullable font) { + if (title.length == 0) { + return font.lineHeight; + } + + NSDictionary<NSAttributedStringKey, id> *attributes = + font == nil ? nil : @{NSFontAttributeName : font}; + CGRect boundingRect = [title boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) + options:NSStringDrawingUsesDeviceMetrics + attributes:attributes + context:nil]; + // Some text height may exceed the UIFont.lineHeight. + // https://developer.apple.com/documentation/uikit/uifont?language=objc + // -------------------- + // | | + // | <= ascender | + // | | <= lineHeight + // -----------------| + // | <= descender | + // -------------------- + // UIFont.lineHeight consist of UIFont.ascender and UIFont.descender. UIFont.descender is the + // bottom offset from the baseline. The boundingRect.origin.y is the amount of space the text will + // occupy in UIFont.descender. So the minimum text view line height is text height + the leftover + // space in the UIFont.descender not occupied by the rendered text. + CGFloat bottomPadding = boundingRect.origin.y - font.descender; + return boundingRect.size.height + bottomPadding; +} + @interface MDCNonselectableTextView : UITextView @end @@ -58,6 +87,7 @@ if (self) { self.autoresizesSubviews = NO; self.clipsToBounds = YES; + self.shouldGroupAccessibilityChildren = YES; self.orderVerticalActionsByEmphasis = NO; self.actionsHorizontalAlignment = MDCContentHorizontalAlignmentTrailing; @@ -1059,6 +1089,41 @@ @implementation MDCNonselectableTextView +#pragma mark - UITextView + +- (void)setAttributedText:(NSAttributedString *)attributedText { + if ([self.attributedText isEqual:attributedText]) { + return; + } + + [super setAttributedText:attributedText]; + [self updateTopInsetAndTextContainerInset:self.textContainerInset]; +} + +- (void)setFont:(UIFont *)font { + if ([self.font isEqual:font]) { + return; + } + + [super setFont:font]; + [self updateTopInsetAndTextContainerInset:self.textContainerInset]; +} + +- (void)setText:(NSString *)text { + if ([self.text isEqual:text]) { + return; + } + + [super setText:text]; + [self updateTopInsetAndTextContainerInset:self.textContainerInset]; +} + +- (void)setTextContainerInset:(UIEdgeInsets)textContainerInset { + [self updateTopInsetAndTextContainerInset:textContainerInset]; +} + +#pragma mark - UIView + // Disabling text selection when selectable is YES, while allowing gestures for inlined links. - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if (UIAccessibilityIsVoiceOverRunning()) { @@ -1086,4 +1151,28 @@ return link != nil; } +#pragma mark - Private + +/** + * Updates the top text inset of the UITextView to avoid rendering text outside the view + * boundary. We need to calculate the text margin when we change the text or the text font. + * + * @note Our title UILabel already has a top margin, so its text won't exceed the parent view's + * boundary. + * + * @param textContainerInset The target text insets to display. It will update the following text + * margin: left, right and bottom. + */ +- (void)updateTopInsetAndTextContainerInset:(UIEdgeInsets)textContainerInset { + // To avoid changing the top margin when the view width changes, we only compare the text height + // for a single line text. + UIFont *font = self.font; + CGFloat singleLineTextViewHeight = SingleLineTextViewHeight(self.text, font); + textContainerInset.top = MAX(0.0f, singleLineTextViewHeight - font.lineHeight); + if (!UIEdgeInsetsEqualToEdgeInsets(super.textContainerInset, textContainerInset)) { + // Note that |self setTextContainerInset:| will call this method. + super.textContainerInset = textContainerInset; + } +} + @end
diff --git a/components/Dialogs/tests/snapshot/MDCAlertControllerLocalizationTests.m b/components/Dialogs/tests/snapshot/MDCAlertControllerLocalizationTests.m index 18db0fa..8624d96 100644 --- a/components/Dialogs/tests/snapshot/MDCAlertControllerLocalizationTests.m +++ b/components/Dialogs/tests/snapshot/MDCAlertControllerLocalizationTests.m
@@ -21,6 +21,7 @@ #import "MDCAlertController+Testing.h" #import "MaterialSnapshot.h" +static NSString *const kThaiTextWithDiacritics = @"นี้ Thai text นี้"; static NSString *const kTitleUrdu = @"عنوان"; static NSString *const kMessageUrdu = @"براہ کرم اپنا نیٹ ورک کنکشن چیک کریں اور دوبارہ کوشش کریں۔براہ کرم اپنا نیٹ ورک کنکشن چیک " @@ -86,6 +87,35 @@ #pragma mark - Tests +/** Verifies the top of Thai attributed message with diacritics won't be cut off. */ +- (void)testPreferredContentSizeWithThaiAttributedMessage { + // When + self.alertController.attributedMessage = + [[NSAttributedString alloc] initWithString:kThaiTextWithDiacritics]; + + // Then + [self generateSizedSnapshotAndVerifyForAlert:self.alertController]; +} + +/** Verifies the top of Thai message with diacritics won't be cut off. */ +- (void)testPreferredContentSizeWithThaiMessage { + // When + self.alertController.message = kThaiTextWithDiacritics; + + // Then + [self generateSizedSnapshotAndVerifyForAlert:self.alertController]; +} + +/** Verifies the top of Thai message and title with diacritics won't be cut off. */ +- (void)testPreferredContentSizeWithThaiMessageAndTitle { + // When + self.alertController.title = kThaiTextWithDiacritics; + self.alertController.message = kThaiTextWithDiacritics; + + // Then + [self generateSizedSnapshotAndVerifyForAlert:self.alertController]; +} + - (void)testPreferredContentSizeWithNotoNastaliqUrdu { // When self.alertController.title = kTitleUrdu;
diff --git a/components/Dialogs/tests/unit/Theming/DialogsMaterialThemingTests.swift b/components/Dialogs/tests/unit/DialogsMaterialThemingTests.swift similarity index 100% rename from components/Dialogs/tests/unit/Theming/DialogsMaterialThemingTests.swift rename to components/Dialogs/tests/unit/DialogsMaterialThemingTests.swift
diff --git a/components/Dividers/.jazzy.yaml b/components/Dividers/.jazzy.yaml deleted file mode 100644 index 5d40598..0000000 --- a/components/Dividers/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: Dividers -umbrella_header: src/MaterialDividers.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/Dividers/README.md b/components/Dividers/README.md deleted file mode 100644 index 55e9a5d..0000000 --- a/components/Dividers/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -# Dividers - -The [Dividers component](https://material.io/go/design-dividers) is yet to be completed, please follow the [tracking issue](https://www.pivotaltracker.com/epic/show/3954818) for more information. -
diff --git a/components/Elevation/tests/unit/MaterialElevationColorTests.m b/components/Elevation/tests/unit/MaterialElevationColorTests.m index 5cda10d..a9e45b2 100644 --- a/components/Elevation/tests/unit/MaterialElevationColorTests.m +++ b/components/Elevation/tests/unit/MaterialElevationColorTests.m
@@ -47,14 +47,11 @@ blue:(CGFloat)0.6 alpha:(CGFloat)0.6]; self.greyScaleColor = [UIColor colorWithWhite:(CGFloat)0.8 alpha:(CGFloat)0.6]; - if (@available(iOS 10.0, *)) { - self.p3DisplayColor = [UIColor colorWithDisplayP3Red:(CGFloat)0.8 - green:(CGFloat)0.7 - blue:(CGFloat)0.5 - alpha:(CGFloat)0.4]; - } else { - self.p3DisplayColor = nil; - } + self.p3DisplayColor = [UIColor colorWithDisplayP3Red:(CGFloat)0.8 + green:(CGFloat)0.7 + blue:(CGFloat)0.5 + alpha:(CGFloat)0.4]; + UIImage *patternImage = fakeImageWithColorAndSize(UIColor.blueColor, CGRectMake(0, 0, 100, 100)); self.patternColor = [UIColor colorWithPatternImage:patternImage]; } @@ -85,10 +82,8 @@ secondColor:expectedRGBColor]; [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedGreyScaleColor secondColor:expectedGreyScaleColor]; - if (@available(iOS 10.0, *)) { - [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor - secondColor:expectedP3Display]; - } + [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor + secondColor:expectedP3Display]; } - (void)testResolvedColorWithLowElevation { @@ -119,10 +114,8 @@ secondColor:expectedRGBColor]; [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedGreyScaleColor secondColor:expectedGreyScaleColor]; - if (@available(iOS 10.0, *)) { - [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor - secondColor:expectedP3Display]; - } + [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor + secondColor:expectedP3Display]; } - (void)testResolvedColorWithHighElevation { @@ -153,10 +146,8 @@ secondColor:expectedRGBColor]; [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedGreyScaleColor secondColor:expectedGreyScaleColor]; - if (@available(iOS 10.0, *)) { - [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor - secondColor:expectedP3Display]; - } + [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor + secondColor:expectedP3Display]; } - (void)testResolvedColorWithNegativeElevation { @@ -176,10 +167,8 @@ secondColor:expectedRGBColor]; [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedGreyScaleColor secondColor:expectedGreyScaleColor]; - if (@available(iOS 10.0, *)) { - [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor - secondColor:expectedP3Display]; - } + [self assertEqualColorsWithFloatPrecisionFirstColor:resolvedP3DisplayColor + secondColor:expectedP3Display]; } - (void)testResolvedColorWithElevationForDynamicColorOniOS13AndAbove {
diff --git a/components/FeatureHighlight/README.md b/components/FeatureHighlight/README.md index 98ef047..5845006 100644 --- a/components/FeatureHighlight/README.md +++ b/components/FeatureHighlight/README.md
@@ -14,9 +14,7 @@ [](https://github.com/material-components/material-components-ios/issues?q=is%3Aopen+is%3Aissue+label%3Atype%3ABug+label%3A%5BFeatureHighlight%5D) -<div class="article__asset article__asset--screenshot"> - <img src="docs/assets/feature_highlight.png" alt="Feature Highlight" width="375"> -</div> +<img src="docs/assets/feature_highlight.png" alt="Feature Highlight" width="375"> The Feature Highlight component is a way to visually highlight a part of the screen in order to introduce users to new features and functionality.
diff --git a/components/FlexibleHeader/README.md b/components/FlexibleHeader/README.md index df2fe42..7e6e2b0 100644 --- a/components/FlexibleHeader/README.md +++ b/components/FlexibleHeader/README.md
@@ -17,9 +17,7 @@ A flexible header is a container view whose height and vertical offset react to UIScrollViewDelegate events. -<div class="article__asset article__asset--screenshot"> - <img src="docs/assets/flexible-header.gif" alt="An animation showing a flexible header appearing and disappearing." width="320"> -</div> +<img src="docs/assets/flexible-header.gif" alt="An animation showing a flexible header appearing and disappearing." width="320"> ## Design & API documentation
diff --git a/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.h b/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.h index ab1b683..8164cf5 100644 --- a/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.h +++ b/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.h
@@ -39,6 +39,7 @@ scrollView.delegate = headerViewController; */ +API_UNAVAILABLE(tvos, watchos) @interface MDCFlexibleHeaderViewController : UIViewController <UIScrollViewDelegate, UITableViewDelegate>
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderControllerIssue176Tests.swift b/components/FlexibleHeader/tests/unit/FlexibleHeaderControllerIssue176Tests.swift index d7907b6..05f373b 100644 --- a/components/FlexibleHeader/tests/unit/FlexibleHeaderControllerIssue176Tests.swift +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderControllerIssue176Tests.swift
@@ -65,8 +65,15 @@ fhvc.didMove(toParent: parentVc) - XCTAssertEqual(fhvc.headerView.trackingScrollView!.contentOffset.y, - -fhvc.headerView.maximumHeight) - XCTAssertEqual(fhvc.view.bounds.size.height, fhvc.headerView.maximumHeight) + if #available(iOS 13, *) { + // TODO(b/184161521): Evaluate why this behavior changed on iOS 13+. + XCTAssertEqual(fhvc.headerView.trackingScrollView!.contentOffset.y, 0) + XCTAssertEqual(fhvc.view.bounds.size.height, fhvc.headerView.minimumHeight) + } else { + XCTAssertEqual( + fhvc.headerView.trackingScrollView!.contentOffset.y, + -fhvc.headerView.maximumHeight) + XCTAssertEqual(fhvc.view.bounds.size.height, fhvc.headerView.maximumHeight) + } } }
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightLegacySafeAreaBehaviorTests.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightLegacySafeAreaBehaviorTests.m index 35f41d8..156b6bb 100644 --- a/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightLegacySafeAreaBehaviorTests.m +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightLegacySafeAreaBehaviorTests.m
@@ -17,8 +17,8 @@ #import "MaterialFlexibleHeader.h" -#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" #import "MDCFlexibleHeaderTopSafeArea.h" +#import "FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" @interface MDCFlexibleHeaderView (UnitTestingPrivateAPIs) @property(nonatomic, strong) MDCFlexibleHeaderTopSafeArea *topSafeArea;
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightTests.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightTests.m index 33c11e1..e0ae838 100644 --- a/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightTests.m +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderHeightTests.m
@@ -17,8 +17,8 @@ #import "MaterialFlexibleHeader.h" -#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" #import "MDCFlexibleHeaderTopSafeArea.h" +#import "FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" @interface MDCFlexibleHeaderView (UnitTestingPrivateAPIs) @property(nonatomic, strong) MDCFlexibleHeaderTopSafeArea *topSafeArea;
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightIncludesSafeAreaTests.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightIncludesSafeAreaTests.m index 7b4572b..e85c010 100644 --- a/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightIncludesSafeAreaTests.m +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightIncludesSafeAreaTests.m
@@ -17,8 +17,8 @@ #import <XCTest/XCTest.h> #import "../../src/private/MDCFlexibleHeaderMinMaxHeight.h" -#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" #import "MDCFlexibleHeaderTopSafeArea.h" +#import "FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" @interface FlexibleHeaderMinMaxHeightIncludesSafeAreaTests : XCTestCase @end
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightTests.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightTests.m index 8aeab02..4b95d6d 100644 --- a/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightTests.m +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderMinMaxHeightTests.m
@@ -17,8 +17,8 @@ #import <XCTest/XCTest.h> #import "../../src/private/MDCFlexibleHeaderMinMaxHeight.h" -#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" #import "MDCFlexibleHeaderTopSafeArea.h" +#import "FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" @interface FlexibleHeaderMinMaxHeightTests : XCTestCase @end
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m index 74fb459..98029de 100644 --- a/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m
@@ -16,10 +16,9 @@ #import <XCTest/XCTest.h> - -#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" -#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeViewController.h" #import "MDCFlexibleHeaderTopSafeArea.h" +#import "FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h" +#import "FlexibleHeaderTopSafeAreaTestsFakeViewController.h" @interface FlexibleHeaderTopSafeAreaTests : XCTestCase @end
diff --git a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h similarity index 94% rename from components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h rename to components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h index 5e6ad85..b5ac5b6 100644 --- a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h +++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h
@@ -14,7 +14,7 @@ #import <Foundation/Foundation.h> -#import "../../../src/private/MDCFlexibleHeaderTopSafeArea.h" +#import "../../src/private/MDCFlexibleHeaderTopSafeArea.h" @interface FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate : NSObject <MDCFlexibleHeaderTopSafeAreaDelegate>
diff --git a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m similarity index 100% rename from components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m rename to components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m
diff --git a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeViewController.h b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeViewController.h similarity index 100% rename from components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeViewController.h rename to components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeViewController.h
diff --git a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeViewController.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeViewController.m similarity index 100% rename from components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeViewController.m rename to components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTestsFakeViewController.m
diff --git a/components/HeaderStackView/README.md b/components/HeaderStackView/README.md index d8a4ca3..027b74a 100644 --- a/components/HeaderStackView/README.md +++ b/components/HeaderStackView/README.md
@@ -13,9 +13,7 @@ The header stack view component is a view that coordinates the layout of two vertically stacked bar views. -<div class="article__asset article__asset--screenshot"> - <img src="docs/assets/header_stack_view.png" alt="Header Stack View" width="320"> -</div> +<img src="docs/assets/header_stack_view.png" alt="Header Stack View" width="320"> ## Design & API Documentation
diff --git a/components/ImageList/.jazzy.yaml b/components/ImageList/.jazzy.yaml deleted file mode 100644 index 0015ba2..0000000 --- a/components/ImageList/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: ImageList -umbrella_header: src/MaterialImageList.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/ImageList/README.md b/components/ImageList/README.md deleted file mode 100644 index 333af44..0000000 --- a/components/ImageList/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -# Image List - -The [Image List component](https://material.io/go/design-image-list) is yet to be completed, please follow the [tracking issue](https://www.pivotaltracker.com/epic/show/3950585) for more information. -
diff --git a/components/LibraryInfo/src/MDCLibraryInfo.m b/components/LibraryInfo/src/MDCLibraryInfo.m index b30653b..a6b1783 100644 --- a/components/LibraryInfo/src/MDCLibraryInfo.m +++ b/components/LibraryInfo/src/MDCLibraryInfo.m
@@ -19,7 +19,7 @@ // This string is updated automatically as a part of the release process and should not be edited // manually. Do not rename this constant or change the formatting without updating the release // scripts. -static NSString* const kMDCLibraryInfoVersionString = @"124.1.1"; +static NSString* const kMDCLibraryInfoVersionString = @"124.2.0"; @implementation MDCLibraryInfo
diff --git a/components/LibraryInfo/tests/unit/LibraryInfoTests.m b/components/LibraryInfo/tests/unit/LibraryInfoTests.m index e0fc188..561830f 100644 --- a/components/LibraryInfo/tests/unit/LibraryInfoTests.m +++ b/components/LibraryInfo/tests/unit/LibraryInfoTests.m
@@ -26,7 +26,7 @@ // Given // This regex pattern does the following: - // Accept: "124.1.1", etc. + // Accept: "124.2.0", etc. // Reject: "0.0.0", "1.2", "1", "-1.2.3", "Hi, I'm a version 1.2.3", "1.2.3 is my version", etc. // // Note the major version must be >= 1 since "0.0.0" is used as the version when something goes
diff --git a/components/List/README.md b/components/List/README.md index 4739ee2..4b0a84f 100644 --- a/components/List/README.md +++ b/components/List/README.md
@@ -155,16 +155,13 @@ **Title text** |`titleLabel` | N/A | N/A **Detail text** |`titleLabel` | N/A | N/A -## Types +**Types** -There are three list types: -1. [Single-line list](#single-line-list) -1. [Two-line list](#two-line-list) -1. [Three-line list](#three-line-list) +There are three list types: 1\. [Single-line list](#single-line-list), 2\. [Two-line list](#two-line-list) 3\. [Three-line list](#three-line-list)  -### Single-line list +## Single-line list Single-line list items contain a maximum of one line of text. @@ -202,7 +199,7 @@ ``` <!--</div>--> -### Two-line list +## Two-line list Two-line list items contain a maximum of two lines of text. @@ -242,7 +239,7 @@ ``` <!--</div>--> -### Three-line list +## Three-line list Three-line list items contains a maximum of three lines of text.
diff --git a/components/List/tests/snapshot/MDCSelfSizingStereoCellSnapshotTests.m b/components/List/tests/snapshot/MDCSelfSizingStereoCellSnapshotTests.m index a643909..3880db0 100644 --- a/components/List/tests/snapshot/MDCSelfSizingStereoCellSnapshotTests.m +++ b/components/List/tests/snapshot/MDCSelfSizingStereoCellSnapshotTests.m
@@ -37,12 +37,9 @@ } - (UITraitCollection *)traitCollection { - if (@available(iOS 10.0, *)) { - UITraitCollection *traitCollection = [UITraitCollection - traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; - return traitCollection; - } - return [super traitCollection]; + UITraitCollection *traitCollection = [UITraitCollection + traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; + return traitCollection; } @end @@ -180,45 +177,41 @@ } - (void)testCellWithDynamicTypeForContentSizeCategoryExtraSmallEnabledForTitleAndDetail { - if (@available(iOS 10.0, *)) { - // Given - MDCSelfSizingStereoCell *cell = [[MDCSelfSizingStereoCell alloc] init]; - self.typographyScheme = - [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; + // Given + MDCSelfSizingStereoCell *cell = [[MDCSelfSizingStereoCell alloc] init]; + self.typographyScheme = + [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; - // When - cell.titleLabel.text = @"Title"; - cell.titleLabel.font = self.typographyScheme.subtitle1; - cell.detailLabel.text = @"Detail"; - cell.detailLabel.font = self.typographyScheme.button; - cell.mdc_adjustsFontForContentSizeCategory = YES; - self.arrayOfCells = @[ cell ]; + // When + cell.titleLabel.text = @"Title"; + cell.titleLabel.font = self.typographyScheme.subtitle1; + cell.detailLabel.text = @"Detail"; + cell.detailLabel.font = self.typographyScheme.button; + cell.mdc_adjustsFontForContentSizeCategory = YES; + self.arrayOfCells = @[ cell ]; - // Then - [self generateSnapshotWithContentSizeCategoryAndNotificationPost:UIContentSizeCategoryExtraSmall - andVerifyForView:self.collectionView]; - } + // Then + [self generateSnapshotWithContentSizeCategoryAndNotificationPost:UIContentSizeCategoryExtraSmall + andVerifyForView:self.collectionView]; } - (void)testCellWithDynamicTypeForContentSizeCategoryExtraLargeEnabledForTitleAndDetail { - if (@available(iOS 10.0, *)) { - // Given - MDCSelfSizingStereoCell *cell = [[MDCSelfSizingStereoCell alloc] init]; - self.typographyScheme = - [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; + // Given + MDCSelfSizingStereoCell *cell = [[MDCSelfSizingStereoCell alloc] init]; + self.typographyScheme = + [[MDCTypographyScheme alloc] initWithDefaults:MDCTypographySchemeDefaultsMaterial201902]; - // When - cell.titleLabel.text = @"Title"; - cell.titleLabel.font = self.typographyScheme.subtitle1; - cell.detailLabel.text = @"Detail"; - cell.detailLabel.font = self.typographyScheme.button; - cell.mdc_adjustsFontForContentSizeCategory = YES; - self.arrayOfCells = @[ cell ]; + // When + cell.titleLabel.text = @"Title"; + cell.titleLabel.font = self.typographyScheme.subtitle1; + cell.detailLabel.text = @"Detail"; + cell.detailLabel.font = self.typographyScheme.button; + cell.mdc_adjustsFontForContentSizeCategory = YES; + self.arrayOfCells = @[ cell ]; - // Then - [self generateSnapshotWithContentSizeCategoryAndNotificationPost:UIContentSizeCategoryExtraLarge - andVerifyForView:self.collectionView]; - } + // Then + [self generateSnapshotWithContentSizeCategoryAndNotificationPost:UIContentSizeCategoryExtraLarge + andVerifyForView:self.collectionView]; } - (void)testPreferredFontForAXXLContentSizeCategory {
diff --git a/components/List/tests/unit/Theming/ListMaterialThemingTests.swift b/components/List/tests/unit/ListMaterialThemingTests.swift similarity index 100% rename from components/List/tests/unit/Theming/ListMaterialThemingTests.swift rename to components/List/tests/unit/ListMaterialThemingTests.swift
diff --git a/components/List/tests/unit/MDCSelfSizingStereoCellTests.m b/components/List/tests/unit/MDCSelfSizingStereoCellTests.m index 27e8b18..be77d3e 100644 --- a/components/List/tests/unit/MDCSelfSizingStereoCellTests.m +++ b/components/List/tests/unit/MDCSelfSizingStereoCellTests.m
@@ -46,12 +46,9 @@ } - (UITraitCollection *)traitCollection { - if (@available(iOS 10.0, *)) { - UITraitCollection *traitCollection = [UITraitCollection - traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; - return traitCollection; - } - return [super traitCollection]; + UITraitCollection *traitCollection = [UITraitCollection + traitCollectionWithPreferredContentSizeCategory:self.contentSizeCategoryOverride]; + return traitCollection; } @end @@ -91,12 +88,8 @@ object:nil]; // Then - // We only test the behavior for iOS10.0+ because we are not able to - // simulate UIApplication in this test for iOS9.0 path. - if (@available(iOS 10.0, *)) { - XCTAssertGreaterThan(cell.titleLabel.font.pointSize, defaultTitleSize); - XCTAssertGreaterThan(cell.detailLabel.font.pointSize, defaultDetailSize); - } + XCTAssertGreaterThan(cell.titleLabel.font.pointSize, defaultTitleSize); + XCTAssertGreaterThan(cell.detailLabel.font.pointSize, defaultDetailSize); } - (void)testAdjustsFontForContentSizeCategoryWhenScaledFontIsUnavailableIsYES {
diff --git a/components/Menus/.jazzy.yaml b/components/Menus/.jazzy.yaml deleted file mode 100644 index ca111d4..0000000 --- a/components/Menus/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: Menus -umbrella_header: src/MaterialMenus.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/Menus/README.md b/components/Menus/README.md deleted file mode 100644 index 24ccefc..0000000 --- a/components/Menus/README.md +++ /dev/null
@@ -1,5 +0,0 @@ -# Menus - -Material will not implement a [Menus component](https://material.io/go/design-menus) -on iOS. For googlers looking for guidance on how to use Menus on iOS, please -visit go/material-ios-guidance-menus.
diff --git a/components/NavigationBar/examples/NavigationBarAlertExample.swift b/components/NavigationBar/examples/NavigationBarAlertExample.swift index f8b9f23..f4eca4e 100644 --- a/components/NavigationBar/examples/NavigationBarAlertExample.swift +++ b/components/NavigationBar/examples/NavigationBarAlertExample.swift
@@ -91,6 +91,8 @@ "breadcrumbs": ["Navigation Bar", "Popover Alert"], "primaryDemo": false, "presentable": false, + "snapshotDelay": 1.0, + "thresholdPercentage": 4.0, ] }
diff --git a/components/NavigationBar/examples/NavigationBarTypicalUseExample.swift b/components/NavigationBar/examples/NavigationBarTypicalUseExample.swift index 80611ad..7c5c170 100644 --- a/components/NavigationBar/examples/NavigationBarTypicalUseExample.swift +++ b/components/NavigationBar/examples/NavigationBarTypicalUseExample.swift
@@ -159,7 +159,7 @@ instructionsAttributedString.addAttributes( instructionsDictionary1, range: NSMakeRange(0, 11)) - let endLength = instructionText.characters.count - 11 + let endLength = instructionText.count - 11 instructionsAttributedString.addAttributes( instructionsDictionary2, range: NSMakeRange(11, endLength))
diff --git a/components/NavigationDrawer/README.md b/components/NavigationDrawer/README.md index 52c5079..a1541b6 100644 --- a/components/NavigationDrawer/README.md +++ b/components/NavigationDrawer/README.md
@@ -61,12 +61,10 @@ While `MDCBottomDrawerViewController` supports the accessibility escape "Z" gesture, it is advisible that the content view controller provides its own dismiss action affordance. Note that it is the responsibility of the header and content view controllers to implement any custom accessibility behavior. -## Types +## Bottom navigation drawer Both bottom navigation drawers and side navigation drawers exist, but we only offer a bottom navigation drawer implementation. -## Bottom navigation drawer - Our bottom navigation drawer implementation is centered around `MDCBottomDrawerViewController`, a `UIViewController` subclass. `MDCBottomDrawerViewController` has a `contentViewController` property, whose view is displayed as the primary content of the drawer, as well as a `headerViewController` property, whose view is positioned above the content view controller and sticks to the top when the drawer is full-screen. For more information on implementing custom view controller classes see [Apple's View Controller Programming Guide](https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/DefiningYourSubclass.html#//apple_ref/doc/uid/TP40007457-CH7-SW1). Bottom navigation drawers are recommended for:
diff --git a/components/NavigationDrawer/tests/unit/MDCNavigationDrawerTest.m b/components/NavigationDrawer/tests/unit/MDCNavigationDrawerTest.m index 613e7d9..6ccb3ec 100644 --- a/components/NavigationDrawer/tests/unit/MDCNavigationDrawerTest.m +++ b/components/NavigationDrawer/tests/unit/MDCNavigationDrawerTest.m
@@ -312,8 +312,15 @@ XCTAssertEqual(presentationController.maximumDrawerHeight, 0); XCTAssertEqual(presentationController.bottomDrawerContainerViewController.maximumDrawerHeight, 0); - XCTAssertEqual(presentationController.bottomDrawerContainerViewController.contentHeightSurplus, - 880); + if (@available(iOS 13, *)) { + // TODO(b/184187506): Determine why this behavior changed on iOS 13+. + XCTAssertEqualWithAccuracy( + presentationController.bottomDrawerContainerViewController.contentHeightSurplus, 400, + 0.01f); + } else { + XCTAssertEqual( + presentationController.bottomDrawerContainerViewController.contentHeightSurplus, 880); + } } else { XCTFail(@"The presentation controller should be class of kind " @"MDCBottomDrawerPresentationController but is %@",
diff --git a/components/PageControl/README.md b/components/PageControl/README.md index 97f5248..08d7c99 100644 --- a/components/PageControl/README.md +++ b/components/PageControl/README.md
@@ -19,9 +19,7 @@ same as a `UIPageControl`, with the addition of a few key methods required to achieve the desired animation of the control. -<div class="article__asset article__asset--screenshot"> - <img src="docs/assets/pagecontrol.gif" alt="An animation demonstrating a page control alternating between three pages." width="190"> -</div> +<img src="docs/assets/pagecontrol.gif" alt="An animation demonstrating a page control alternating between three pages." width="190"> ## Design & API documentation
diff --git a/components/PageControl/tests/unit/PageControlExampleTests.m b/components/PageControl/tests/unit/PageControlExampleTests.m index c75325b..6b43cdc 100644 --- a/components/PageControl/tests/unit/PageControlExampleTests.m +++ b/components/PageControl/tests/unit/PageControlExampleTests.m
@@ -81,7 +81,12 @@ [nativePageControl sizeToFit]; CGRect frame = CGRectIntegral(pageControl.frame); XCTAssertEqual(frame.size.height, 48.0); - XCTAssertEqual(frame.size.width, nativePageControl.frame.size.width); + if (@available(iOS 14, *)) { + XCTAssertEqual(frame.size.width, 7); + XCTAssertEqual(nativePageControl.frame.size.width, 85); + } else { + XCTAssertEqual(frame.size.width, nativePageControl.frame.size.width); + } // Test both controls with 4 pages. pageControl.numberOfPages = 4; @@ -90,7 +95,12 @@ [nativePageControl sizeToFit]; frame = CGRectIntegral(pageControl.frame); XCTAssertEqual(frame.size.height, 48.0); - XCTAssertEqual(frame.size.width, nativePageControl.frame.size.width); + if (@available(iOS 14, *)) { + XCTAssertEqual(frame.size.width, 55); + XCTAssertEqual(nativePageControl.frame.size.width, 141); + } else { + XCTAssertEqual(frame.size.width, nativePageControl.frame.size.width); + } // Test with different number of pages for each control. pageControl.numberOfPages = 4;
diff --git a/components/ProgressView/tests/unit/Theming/ProgressViewMaterialThemingTests.m b/components/ProgressView/tests/unit/ProgressViewMaterialThemingTests.m similarity index 98% rename from components/ProgressView/tests/unit/Theming/ProgressViewMaterialThemingTests.m rename to components/ProgressView/tests/unit/ProgressViewMaterialThemingTests.m index 89afcca..13079ca 100644 --- a/components/ProgressView/tests/unit/Theming/ProgressViewMaterialThemingTests.m +++ b/components/ProgressView/tests/unit/ProgressViewMaterialThemingTests.m
@@ -14,9 +14,10 @@ #import <XCTest/XCTest.h> -#import "MaterialContainerScheme.h" -#import "MaterialProgressView+Theming.h" #import "MaterialProgressView.h" +#import "MaterialProgressView+Theming.h" +#import "MaterialColorScheme.h" +#import "MaterialContainerScheme.h" // The ratio by which to desaturate the progress tint color to obtain the default track tint color. static const CGFloat MDCProgressViewTrackColorDesaturation = (CGFloat)0.3;
diff --git a/components/README.md b/components/README.md index f4f6bab..ec74d67 100644 --- a/components/README.md +++ b/components/README.md
@@ -4,6 +4,14 @@ Material Components for iOS are written in Objective-C and support Swift and Interface Builder. +Some Material components are intentionally not made available on iOS because +you should use native components on Apple's platforms instead. This includes +checkboxes, radio buttons, and switches (use UISwitch and UITableView instead) +and data tables and image lists (use UITableView / UICollectionView instead). + +If a component is missing and not listed above, you can file a feature request +via https://github.com/material-components/material-components-ios/issues/new?assignees=&labels=&template=Feature_request.md + <a name="components"></a> <!--{: .jumplink }-->
diff --git a/components/RadioButton/.jazzy.yaml b/components/RadioButton/.jazzy.yaml deleted file mode 100644 index a0cb38a..0000000 --- a/components/RadioButton/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: RadioButton -umbrella_header: src/MaterialRadioButton.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/RadioButton/README.md b/components/RadioButton/README.md deleted file mode 100644 index e9ee403..0000000 --- a/components/RadioButton/README.md +++ /dev/null
@@ -1,3 +0,0 @@ -# Radio Button - -The [Radio Button component](https://material.io/go/design-radio-buttons) will not be implemented on iOS [to better adapt to the platform](https://material.io/design/platform-guidance/cross-platform-adaptation.html). Apps should make use of a List with checkmark icons instead.
diff --git a/components/Shadow/README.md b/components/Shadow/README.md new file mode 100644 index 0000000..52d558c --- /dev/null +++ b/components/Shadow/README.md
@@ -0,0 +1,76 @@ +# Shadow + +Provides lightweight classes that hold shadow properties that each correspond to an elevation. + +This library provides two immutable types that are created via builder APIs: +MDCShadowsCollection and MDCShadow. This library works with standard CALayer shadow APIs in order +to optimize for performance. UIView’s layer shadow properties are set directly, including: +shadowOffset, shadowRadius, shadowOpacity, shadowColor, and shadowPath. We ensure that +shadowPath is consistently set alongside the other properties in order for shadows to benefit +from the performance gains that shadowPath provides. + +This library is part of an effort to simplify shadows in MDC, with the intent of deleting the +MDCShadowLayer component entirely. + +## Usage + +We want to provide a simple API to integrate this shadow solution. Therefore, we leaned on providing only one type of configuration method that should be re-called in the view’s lifecycle. Namely, the method should be the C function MDCConfigureShadowForView. + +MDCConfigureShadowForView should be called in the start of the view’s lifecycle, i.e. during initialization, so that the shadowRadius, shadowOffset, shadowColor, and shadowOpacity are set on the layer. + +MDCConfigureShadowForView should also be called when the elevation is changed for the view i.e. it is set by the client, or there is a state change that also changes the elevation. This is to ensure that the right shadow values for that elevation are set on the layer. +Lastly, MDCConfigureShadowForView should be called in layoutSubviews, to ensure that the shadowPath is set using the most upto date bounds and cornerRadius of the view. + +### Importing + +Before using Shadow, you'll need to import it: + +#### Swift +```swift +import MaterialComponents + +var shadowsCollection: MDCShadowsCollection +let shadow = MDCShadowBuilder.builder(withOpacity:0.1, radius: 0.2, offset: CGSize(0.3, 0.4)).build() +let shadowsBuilder = MDCShadowsCollectionBuilder.builder(withShadow:shadow forElevation:0) +let shadowValuesForElevation = [1: MDCShadowBuilder.builder(withOpacity:0.3, + radius: 0.4, + offset: CGSize(0.5, 0.6)).build()] +shadowsBuilder.addShadows(forElevation:shadowValuesForElevation) +shadowsCollection = shadowsBuilder.build() + +... + +func updateShadow() { + MDCConfigureShadowForView(self, + self.shadowsCollection.shadow(forElevation:self.mdc_currentElevation), + self.shadowColor) +} +``` + +#### Objective-C +```objc +#import "MaterialShadow.h" + +MDCShadowsCollection *shadowsCollection; +MDCShadow *shadow = + [[MDCShadowBuilder builderWithOpacity:0.1 + radius:0.2 + offset:CGSizeMake(0.3, 0.4)] build]; +MDCShadowsCollectionBuilder *shadowsBuilder = + [MDCShadowsCollectionBuilder builderWithShadow:shadow forElevation:0]; +NSDictionary<NSNumber *, MDCShadow *> *shadowValuesForElevation = @{ + @1 : [[MDCShadowBuilder builderWithOpacity:0.3 + radius:0.4 + offset:CGSizeMake(0.5, 0.6)] build], +}; +[shadowsBuilder addShadowsForElevations:shadowValuesForElevation]; +shadowsCollection = [shadowsBuilder build]; + +... + +- (void)updateShadow { + MDCConfigureShadowForView(self, + [self.shadowsCollection shadowForElevation:self.mdc_currentElevation], + self.shadowColor); +} +```
diff --git a/components/Shadow/examples/ShadowTypicalUseExample.swift b/components/Shadow/examples/ShadowTypicalUseExample.swift new file mode 100644 index 0000000..74456ff --- /dev/null +++ b/components/Shadow/examples/ShadowTypicalUseExample.swift
@@ -0,0 +1,342 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 UIKit +import MaterialComponents.MaterialShadow +import MaterialComponents.MaterialContainerScheme + +/// Typical use-case for a view with Material Shadows at a fixed elevation. +final class ShadowedView: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + layer.cornerRadius = 4 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) is unavailable") + } + + override func layoutSubviews() { + super.layoutSubviews() + MDCConfigureShadow( + for: self, shadow: MDCShadowsCollectionDefault().shadow(forElevation: 1), + color: MDCShadowColor()) + } +} + +/// Typical use-case for a shaped view with Material Shadows. +final class ShapedView: UIView { + let shapeLayer = CAShapeLayer() + + override init(frame: CGRect) { + super.init(frame: frame) + layer.addSublayer(shapeLayer) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) is unavailable") + } + + override var backgroundColor: UIColor? { + get { + guard let color = shapeLayer.fillColor else { return nil } + return UIColor(cgColor: color) + } + set { + shapeLayer.fillColor = newValue?.cgColor + } + } + + override func layoutSubviews() { + super.layoutSubviews() + guard let path = polygonPath(bounds: self.bounds, numSides: 3, numPoints: 3) else { return } + shapeLayer.path = path + + MDCConfigureShadow( + for: self, shadow: MDCShadowsCollectionDefault().shadow(forElevation: 1), + color: MDCShadowColor(), + path: path) + } +} + +/// More complex use-case for a view with a custom shape which animates. +final class AnimatedShapedView: UIView { + let shapeLayer = CAShapeLayer() + let firstNumSides = 3 + let lastNumSides = 12 + let animationStepDuration: CFTimeInterval = 0.6 + + override init(frame: CGRect) { + super.init(frame: frame) + layer.addSublayer(shapeLayer) + updatePathAndAnimations() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) is unavailable") + } + + override var backgroundColor: UIColor? { + get { + guard let color = shapeLayer.fillColor else { return nil } + return UIColor(cgColor: color) + } + set { + shapeLayer.fillColor = newValue?.cgColor + } + } + + override func layoutSubviews() { + super.layoutSubviews() + updatePathAndAnimations() + } + + private func updatePathAndAnimations() { + guard + let startPath = polygonPath( + bounds: bounds, numSides: firstNumSides, numPoints: lastNumSides) + else { return } + shapeLayer.path = startPath + MDCConfigureShadow( + for: self, shadow: MDCShadowsCollectionDefault().shadow(forElevation: 1), + color: MDCShadowColor(), + path: startPath) + + var polygonPaths = (firstNumSides...lastNumSides).map { + polygonPath(bounds: bounds, numSides: $0, numPoints: lastNumSides) + } + polygonPaths.shuffle() + var beginTime: CFTimeInterval = 0 + var pathAnimations: [CAAnimation] = [] + var shadowPathAnimations: [CAAnimation] = [] + for (i, polygonPath) in polygonPaths.enumerated() { + let fromValue = i == 0 ? polygonPaths[polygonPaths.count - 1] : polygonPaths[i - 1] + let toValue = polygonPath + let pathAnimation = CABasicAnimation(keyPath: "path") + pathAnimation.fromValue = fromValue + pathAnimation.toValue = toValue + pathAnimation.beginTime = beginTime + pathAnimation.duration = animationStepDuration + pathAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) + pathAnimations.append(pathAnimation) + let shadowPathAnimation = pathAnimation.copy() as! CABasicAnimation + shadowPathAnimation.keyPath = "shadowPath" + shadowPathAnimations.append(shadowPathAnimation) + beginTime += animationStepDuration + } + + let pathAnimationGroup = CAAnimationGroup() + pathAnimationGroup.animations = pathAnimations + pathAnimationGroup.duration = animationStepDuration * CFTimeInterval(pathAnimations.count) + pathAnimationGroup.repeatCount = .greatestFiniteMagnitude + shapeLayer.add(pathAnimationGroup, forKey: "path") + + let shadowPathAnimationGroup = CAAnimationGroup() + shadowPathAnimationGroup.animations = shadowPathAnimations + shadowPathAnimationGroup.duration = + animationStepDuration * CFTimeInterval(pathAnimations.count) + shadowPathAnimationGroup.repeatCount = .greatestFiniteMagnitude + layer.add(shadowPathAnimationGroup, forKey: "shadowPath") + } +} + +/// Returns a regular polygon within `bounds` having `numSides` sides. +/// +/// If `numSides` < 3 or `numPoints` < `numSides`, returns nil. +/// +/// If `numPoints` > `numSides`, the polygon will invisibly repeat +/// points along the vertices to ensure it has `numPoints` points. +/// This allows smooth animations between multiple polygons with +/// differing number of sides. +func polygonPath(bounds: CGRect, numSides: Int, numPoints: Int) -> CGPath? { + guard numSides > 2 else { return nil } + guard numPoints >= numSides else { return nil } + let xRadius = bounds.width / 2 + let yRadius = bounds.height / 2 + let path = UIBezierPath() + for pointIdx in 0..<numPoints { + // Map pointIdx to a float in the range [0, 1]. + let pointProgress = CGFloat(pointIdx) / CGFloat(numPoints - 1) + // Choose the closest vertex of the polygon. + let sideIdx = round(pointProgress * CGFloat(numSides - 1)) + let theta = CGFloat(2) * CGFloat.pi / CGFloat(numSides) * sideIdx + let x = bounds.midX + xRadius * cos(theta) + let y = bounds.midY + yRadius * sin(theta) + let point = CGPoint(x: x, y: y) + if pointIdx == 0 { + path.move(to: point) + } else if pointIdx < numPoints { + path.addLine(to: point) + } + } + path.close() + return path.cgPath +} + +@available(iOS 12.0, *) +final class ShadowTypicalUseExample: UIViewController { + enum ExampleType: Int { + case typical, shaped, animated + } + + private typealias Example = (label: String, type: ExampleType) + private let examples: [Example] = [ + ("Typical", .typical), + ("Shaped", .shaped), + ("Animated", .animated), + ] + + private let containerScheme = MDCContainerScheme() + + private lazy var typicalView: UIView = { + let result = ShadowedView() + result.translatesAutoresizingMaskIntoConstraints = false + result.backgroundColor = containerScheme.colorScheme.primaryColor + return result + }() + + private lazy var shapedView: UIView = { + let result = ShapedView() + result.translatesAutoresizingMaskIntoConstraints = false + result.backgroundColor = containerScheme.colorScheme.primaryColor + return result + }() + + private lazy var animatedView: UIView = { + let result = AnimatedShapedView() + result.translatesAutoresizingMaskIntoConstraints = false + result.backgroundColor = containerScheme.colorScheme.primaryColor + return result + }() + + private lazy var typeControl: UISegmentedControl = { + let result = UISegmentedControl(items: examples.map { $0.label }) + result.backgroundColor = containerScheme.colorScheme.primaryColor + result.translatesAutoresizingMaskIntoConstraints = false + if #available(iOS 13, *) { + result.selectedSegmentTintColor = containerScheme.colorScheme.surfaceColor + } + result.setTitleTextAttributes( + [ + .foregroundColor: containerScheme.colorScheme.onPrimaryColor + ], + for: .normal) + result.setTitleTextAttributes( + [ + .foregroundColor: containerScheme.colorScheme.onSurfaceColor + ], + for: .selected) + result.selectedSegmentIndex = 0 + return result + }() + + private let topSpacerLayoutGuide = UILayoutGuide() + private let contentLayoutGuide = UILayoutGuide() + private let bottomSpacerLayoutGuide = UILayoutGuide() + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = containerScheme.colorScheme.backgroundColor + view.addSubview(typicalView) + view.addSubview(shapedView) + view.addSubview(animatedView) + view.addLayoutGuide(topSpacerLayoutGuide) + view.addLayoutGuide(contentLayoutGuide) + view.addLayoutGuide(bottomSpacerLayoutGuide) + view.addSubview(typeControl) + updateExampleType() + typeControl.addTarget(self, action: #selector(updateExampleType), for: .valueChanged) + let safeAreaLayoutGuide = view.safeAreaLayoutGuide + NSLayoutConstraint.activate([ + // Top spacer. + topSpacerLayoutGuide.topAnchor.constraint( + equalToSystemSpacingBelow: safeAreaLayoutGuide.topAnchor, multiplier: 1), + topSpacerLayoutGuide.heightAnchor.constraint(greaterThanOrEqualToConstant: 20), + topSpacerLayoutGuide.bottomAnchor.constraint(equalTo: contentLayoutGuide.topAnchor), + + // Content. + contentLayoutGuide.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor), + contentLayoutGuide.widthAnchor.constraint(equalTo: contentLayoutGuide.heightAnchor), + contentLayoutGuide.widthAnchor.constraint(greaterThanOrEqualToConstant: 100), + contentLayoutGuide.widthAnchor.constraint( + lessThanOrEqualTo: safeAreaLayoutGuide.widthAnchor, constant: -40), + + typicalView.centerXAnchor.constraint(equalTo: contentLayoutGuide.centerXAnchor), + typicalView.centerYAnchor.constraint(equalTo: contentLayoutGuide.centerYAnchor), + typicalView.widthAnchor.constraint(equalTo: contentLayoutGuide.widthAnchor), + typicalView.heightAnchor.constraint(equalTo: contentLayoutGuide.heightAnchor), + + shapedView.centerXAnchor.constraint(equalTo: contentLayoutGuide.centerXAnchor), + shapedView.centerYAnchor.constraint(equalTo: contentLayoutGuide.centerYAnchor), + shapedView.widthAnchor.constraint(equalTo: contentLayoutGuide.widthAnchor), + shapedView.heightAnchor.constraint(equalTo: contentLayoutGuide.heightAnchor), + + animatedView.centerXAnchor.constraint(equalTo: contentLayoutGuide.centerXAnchor), + animatedView.centerYAnchor.constraint(equalTo: contentLayoutGuide.centerYAnchor), + animatedView.widthAnchor.constraint(equalTo: contentLayoutGuide.widthAnchor), + animatedView.heightAnchor.constraint(equalTo: contentLayoutGuide.heightAnchor), + + // Bottom spacer. + bottomSpacerLayoutGuide.topAnchor.constraint(equalTo: contentLayoutGuide.bottomAnchor), + + // Ensure the top spacer and bottom spacer both have the same height (to center the content). + bottomSpacerLayoutGuide.heightAnchor.constraint(equalTo: topSpacerLayoutGuide.heightAnchor), + + // Segmented type control. + typeControl.topAnchor.constraint( + equalToSystemSpacingBelow: bottomSpacerLayoutGuide.bottomAnchor, + multiplier: 1), + typeControl.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor), + typeControl.widthAnchor.constraint(lessThanOrEqualTo: safeAreaLayoutGuide.widthAnchor), + + safeAreaLayoutGuide.bottomAnchor.constraint( + equalToSystemSpacingBelow: typeControl.bottomAnchor, multiplier: 1), + ]) + } + + @objc func updateExampleType() { + guard let exampleType = ExampleType(rawValue: typeControl.selectedSegmentIndex) else { return } + switch exampleType { + case .typical: + typicalView.isHidden = false + shapedView.isHidden = true + animatedView.isHidden = true + case .shaped: + typicalView.isHidden = true + shapedView.isHidden = false + animatedView.isHidden = true + case .animated: + typicalView.isHidden = true + shapedView.isHidden = true + animatedView.isHidden = false + } + } +} + +// MARK: Catalog by Convensions +@available(iOS 12.0, *) +extension ShadowTypicalUseExample { + + @objc class func catalogMetadata() -> [String: Any] { + return [ + "breadcrumbs": ["Shadow", "New Shadow"], + "primaryDemo": true, + "presentable": false, + ] + } + + @objc class func minimumOSVersion() -> OperatingSystemVersion { + return OperatingSystemVersion(majorVersion: 12, minorVersion: 0, patchVersion: 0) + } +}
diff --git a/components/Shadow/src/MDCShadow.h b/components/Shadow/src/MDCShadow.h index d4a7fb3..deaa46c 100644 --- a/components/Shadow/src/MDCShadow.h +++ b/components/Shadow/src/MDCShadow.h
@@ -15,11 +15,14 @@ #import <UIKit/UIKit.h> /** - Immutable value type holding shadow metrics to apply to a view's layer. Use - `MDCShadowForElevation()` or `MDCShadowBuilder` to create this object. + An immutable shadow object that consists of shadow properties (opacity, radius, offset). + + To generate a shadow instance, please use the MDCShadowBuilder APIs. */ __attribute__((objc_subclassing_restricted)) @interface MDCShadow : NSObject +- (nonnull instancetype)init NS_UNAVAILABLE; + /** CALayer.shadowOpacity */ @property(nonatomic, readonly) CGFloat opacity; @@ -29,8 +32,6 @@ /** CALayer.shadowOffset */ @property(nonatomic, readonly) CGSize offset; -- (nonnull instancetype)init NS_UNAVAILABLE; - @end /** @@ -50,15 +51,9 @@ /** Returns an immutable value type containing a snapshot of the values in this object. */ - (nonnull MDCShadow *)build; +/** Returns a builder with the provided opacity, radius, and offset properties. */ ++ (nonnull MDCShadowBuilder *)builderWithOpacity:(CGFloat)opacity + radius:(CGFloat)radius + offset:(CGSize)offset; + @end - -/** - Default color for a Material shadow. On iOS >= 13, this is a dynamic color. - */ -FOUNDATION_EXTERN UIColor *_Nonnull MDCShadowColor(void); - -/** - Returns an `MDCShadow` representing the Material shadow metrics for the given elevation (in - points). - */ -FOUNDATION_EXTERN MDCShadow *_Nonnull MDCShadowForElevation(CGFloat elevation);
diff --git a/components/Shadow/src/MDCShadow.m b/components/Shadow/src/MDCShadow.m index 897165f..94a6144 100644 --- a/components/Shadow/src/MDCShadow.m +++ b/components/Shadow/src/MDCShadow.m
@@ -14,9 +14,6 @@ #import "MDCShadow.h" -#import "MaterialAvailability.h" -#import "MDCShadow+Internal.h" - @implementation MDCShadow - (instancetype)initWithOpacity:(CGFloat)opacity radius:(CGFloat)radius offset:(CGSize)offset { @@ -59,68 +56,14 @@ return [[MDCShadow alloc] initWithOpacity:self.opacity radius:self.radius offset:self.offset]; } ++ (MDCShadowBuilder *)builderWithOpacity:(CGFloat)opacity + radius:(CGFloat)radius + offset:(CGSize)offset { + MDCShadowBuilder *builder = [[MDCShadowBuilder alloc] init]; + builder.opacity = opacity; + builder.radius = radius; + builder.offset = offset; + return builder; +} + @end - -static UIColor *LightStyleShadowColor(void) { - static UIColor *lightStyleShadowColor; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - lightStyleShadowColor = [UIColor colorWithRed:0.235 green:0.251 blue:0.263 alpha:1]; - }); - return lightStyleShadowColor; -} - -UIColor *MDCShadowColor(void) { -#if MDC_AVAILABLE_SDK_IOS(13_0) - if (@available(iOS 13.0, *)) { - return [UIColor colorWithDynamicProvider:^(UITraitCollection *traitCollection) { - switch (traitCollection.userInterfaceStyle) { - case UIUserInterfaceStyleUnspecified: - __attribute__((fallthrough)); - case UIUserInterfaceStyleLight: - return LightStyleShadowColor(); - case UIUserInterfaceStyleDark: - return UIColor.blackColor; - } - __builtin_unreachable(); - }]; - } -#endif // MDC_AVAILABLE_SDK_IOS(13_0) - return LightStyleShadowColor(); -} - -static int ShadowElevationToLevel(CGFloat elevation) { - if (elevation < 1) { - return 0; - } - if (elevation < 3) { - return 1; - } - if (elevation < 6) { - return 2; - } - if (elevation < 8) { - return 3; - } - if (elevation < 12) { - return 4; - } - return 5; -} - -MDCShadow *MDCShadowForElevation(CGFloat elevation) { - static NSArray *shadowLevels; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - shadowLevels = @[ - [[MDCShadow alloc] initWithOpacity:0 radius:0 offset:CGSizeMake(0, 0)], - [[MDCShadow alloc] initWithOpacity:0.43 radius:2.5 offset:CGSizeMake(0, 1)], - [[MDCShadow alloc] initWithOpacity:0.4 radius:3.25 offset:CGSizeMake(0, 1.25)], - [[MDCShadow alloc] initWithOpacity:0.34 radius:4.75 offset:CGSizeMake(0, 2.25)], - [[MDCShadow alloc] initWithOpacity:0.42 radius:6 offset:CGSizeMake(0, 3)], - [[MDCShadow alloc] initWithOpacity:0.4 radius:7.25 offset:CGSizeMake(0, 5)], - ]; - }); - int shadowLevel = ShadowElevationToLevel(elevation); - return shadowLevels[shadowLevel]; -}
diff --git a/components/Shadow/src/MDCShadowConfiguring.h b/components/Shadow/src/MDCShadowConfiguring.h deleted file mode 100644 index e1910ee..0000000 --- a/components/Shadow/src/MDCShadowConfiguring.h +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright 2021-present the Material Components for iOS authors. 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 <UIKit/UIKit.h> - -@class MDCShadow; - -/** - Given a view and a shadow color (e.g. `MDCShadowColor()`) along with an elevation, updates - the shadow properties of `view.layer`: - - * shadowColor - * shadowOpacity - * shadowRadius - * shadowOffset - * shadowPath - - `shadowPath` will be set to the current bounds of the given view (including rounded - corners if set on view.layer). - - TODO(b/182581383): maskedCorners, cornerCurve, and cornerCurveExpansionFactor are not - yet supported. - - If `elevation` is < 1, disables the view's shadow. Otherwise, enables the shadow. - - Call this function from your `UIView` subclass's `-layoutSubviews` to update `shadowPath` - whenever the view's bounds change. - */ -FOUNDATION_EXTERN void MDCConfigureShadowForViewWithElevation(UIView *_Nonnull view, - UIColor *_Nonnull shadowColor, - CGFloat elevation) - NS_SWIFT_NAME(MDCConfigureShadow(for:color:elevation:)); - -/** - Given a view and a shadow color (e.g. `MDCShadowColor()`) along with an `MDCShadow` value, updates - the shadow properties of `view.layer`: - - * shadowColor - * shadowOpacity - * shadowRadius - * shadowOffset - * shadowPath - - `shadowPath` will be set to the current bounds of the given view (including rounded - corners if set on view.layer). - - TODO(b/182581383): maskedCorners, cornerCurve, and cornerCurveExpansionFactor are not - yet supported. - - Call this function from your `UIView` subclass's `-layoutSubviews` to update `shadowPath` - whenever the view's bounds change. - */ -FOUNDATION_EXTERN void MDCConfigureShadowForViewWithShadow(UIView *_Nonnull view, - UIColor *_Nonnull shadowColor, - MDCShadow *_Nonnull shadow) - NS_SWIFT_NAME(MDCConfigureShadow(for:color:shadow:)); - -/** - Given a view, a shadow color (e.g. `MDCShadowColor()`), an `MDCShadow` value, and a `path` in the - view's coordinate space representing the shape of the view, updates the shadow properties of - `view.layer`: - - * shadowColor - * shadowOpacity - * shadowRadius - * shadowOffset - * shadowPath - - Call this function from your `UIView` subclass's `-layoutSubviews` to update `shadowPath` - whenever the view's bounds or shape changes. - */ -FOUNDATION_EXTERN void MDCConfigureShadowForViewWithShadowAndPath(UIView *_Nonnull view, - UIColor *_Nonnull shadowColor, - MDCShadow *_Nonnull shadow, - CGPathRef _Nonnull path) - NS_SWIFT_NAME(MDCConfigureShadow(for:color:shadow:path:));
diff --git a/components/Shadow/src/MDCShadowConfiguring.m b/components/Shadow/src/MDCShadowConfiguring.m deleted file mode 100644 index c2414f1..0000000 --- a/components/Shadow/src/MDCShadowConfiguring.m +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2021-present the Material Components for iOS authors. 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 "MDCShadowConfiguring.h" - -#import "MaterialAvailability.h" -#import "MDCShadow.h" - -void MDCConfigureShadowForViewWithElevation(UIView *view, UIColor *shadowColor, CGFloat elevation) { - MDCShadow *shadow = MDCShadowForElevation(elevation); - if (!shadow) { - view.layer.shadowColor = nil; - view.layer.shadowOpacity = 0; - view.layer.shadowRadius = 0; - view.layer.shadowOffset = CGSizeZero; - view.layer.shadowPath = nil; - return; - } - MDCConfigureShadowForViewWithShadow(view, shadowColor, shadow); -} - -void MDCConfigureShadowForViewWithShadow(UIView *view, UIColor *shadowColor, MDCShadow *shadow) { - // Support views both with and without cornerRadius set. - UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:view.bounds - cornerRadius:view.layer.cornerRadius]; - MDCConfigureShadowForViewWithShadowAndPath(view, shadowColor, shadow, path.CGPath); -} - -void MDCConfigureShadowForViewWithShadowAndPath(UIView *view, UIColor *shadowColor, - MDCShadow *shadow, CGPathRef path) { -#if MDC_AVAILABLE_SDK_IOS(13_0) - if (@available(ios 13.0, *)) { - shadowColor = [shadowColor resolvedColorWithTraitCollection:view.traitCollection]; - } -#endif // MDC_AVAILABLE_SDK_IOS(13_0) - view.layer.shadowColor = shadowColor.CGColor; - view.layer.shadowOpacity = shadow.opacity; - view.layer.shadowRadius = shadow.radius; - view.layer.shadowOffset = shadow.offset; - view.layer.shadowPath = path; -}
diff --git a/components/Shadow/src/MDCShadowsCollection.h b/components/Shadow/src/MDCShadowsCollection.h new file mode 100644 index 0000000..d69730c --- /dev/null +++ b/components/Shadow/src/MDCShadowsCollection.h
@@ -0,0 +1,145 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 <UIKit/UIKit.h> + +#import "MDCShadow.h" + +/** + An immutable shadows collection object that encapsulates a storage of shadows correlating to + elevation values. + + To apply a shadow on a view, please see and use the C methods @c MDCConfigureShadowForView and + @c MDCConfigureShadowForViewWithPath. + */ +__attribute__((objc_subclassing_restricted)) @interface MDCShadowsCollection : NSObject + +- (nonnull instancetype)init NS_UNAVAILABLE; + +/** + Returns an MDCShadow instance representing the shadow properties for the given elevation (in + points) by fetching from the @c shadowsCollection container holding elevation to MDCShadow instance + bindings. + + Note: If the provided elevation is not stored, the shadow properties that are set are of the + nearest elevation above the provided elevation. i.e. if elevations 1 and 3 are set, and an + elevation of 2 is provided as input, the shadow properties set will be of elevation 3. If the + provided elevation is above the highest elevation value that is set, then the shadow properties set + will be of the highest elevation. + */ +- (nonnull MDCShadow *)shadowForElevation:(CGFloat)elevation; + +@end + +/** + A shadows collection object builder that generates an MDCShadowsCollection instance using the @c + build method. The object allows to add shadows for a given elevation. + + To ensure no nullability situations, please instantiate the builder using @c + builderWithShadow:forElevation and provide an initial MDCShadow instance. + */ +__attribute__((objc_subclassing_restricted)) @interface MDCShadowsCollectionBuilder : NSObject + +- (nonnull instancetype)init NS_UNAVAILABLE; + +/** + Adds a shadow for the given elevation. + + @param shadow An MDCShadow object consisting of shadow properties such as radius, opacity, and + offset. + @param elevation The elevation provided in points (dp). + */ +- (void)addShadow:(MDCShadow *_Nonnull)shadow forElevation:(CGFloat)elevation; + +/** + Adds a dictionary of shadows with their correlating elevations to the shadows collection. + + @param shadowsForElevations A dictionary holding NSNumber elevation value keys, and their values + are MDCShadow objects correlating to their elevation key. + */ +- (void)addShadowsForElevations: + (NSDictionary<NSNumber *, MDCShadow *> *_Nonnull)shadowsForElevations; + +/** + Creates an initial MDCShadowsCollectionBuilder by providing it an initial MDCShadow object and its + correlating elevation. + + @param shadow An MDCShadow object consisting of shadow properties such as radius, opacity, and + offset. + @param elevation The elevation provided in points (dp). + */ ++ (nonnull MDCShadowsCollectionBuilder *)builderWithShadow:(MDCShadow *_Nonnull)shadow + forElevation:(CGFloat)elevation; + +/** + Builds and returns an MDCShadowsCollection instance given the provided shadows using the + @c addShadow:forElevation and @c addShadowsForElevations: APIs. + */ +- (nonnull MDCShadowsCollection *)build; + +@end + +/** + Given a view, MDCShadow instance, and a shadow color (e.g. `MDCShadowColor()`), updates the shadow + properties of `view.layer`: + + * shadowColor + * shadowOpacity + * shadowRadius + * shadowOffset + * shadowPath + + `shadowPath` will be set to the current bounds of the given view (including rounded + corners if set on view.layer). + + TODO(b/182581383): maskedCorners, cornerCurve, and cornerCurveExpansionFactor are not + yet supported. + + Call this function from your `UIView` subclass's `-layoutSubviews` to update `shadowPath` + whenever the view's bounds change. + */ +FOUNDATION_EXTERN void MDCConfigureShadowForView(UIView *_Nonnull view, MDCShadow *_Nonnull shadow, + UIColor *_Nonnull shadowColor) + NS_SWIFT_NAME(MDCConfigureShadow(for:shadow:color:)); + +/** + Given a view, MDCShadow instance, a shadow color (e.g. `MDCShadowColor()`), and a `path` in the + view's coordinate space representing the shape of the view, updates the shadow properties of + `view.layer`: + + * shadowColor + * shadowOpacity + * shadowRadius + * shadowOffset + * shadowPath + + Call this function from your `UIView` subclass's `-layoutSubviews` to update `shadowPath` + whenever the view's bounds or shape changes. + */ +FOUNDATION_EXTERN void MDCConfigureShadowForViewWithPath(UIView *_Nonnull view, + MDCShadow *_Nonnull shadow, + UIColor *_Nonnull shadowColor, + CGPathRef _Nonnull path) + NS_SWIFT_NAME(MDCConfigureShadow(for:shadow:color:path:)); + +/** + Default color for a Material shadow. On iOS >= 13, this is a dynamic color. + */ +FOUNDATION_EXTERN UIColor *_Nonnull MDCShadowColor(void); + +/** + Returns an MDCShadowsCollection instance with predefined defaults of shadow properties (opacity, + radius, offset) for elevations. + */ +FOUNDATION_EXTERN MDCShadowsCollection *_Nonnull MDCShadowsCollectionDefault(void);
diff --git a/components/Shadow/src/MDCShadowsCollection.m b/components/Shadow/src/MDCShadowsCollection.m new file mode 100644 index 0000000..5b22fca --- /dev/null +++ b/components/Shadow/src/MDCShadowsCollection.m
@@ -0,0 +1,165 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 "MDCShadowsCollection.h" + +#import "MaterialAvailability.h" +#import "MDCShadow.h" + +@implementation MDCShadowsCollection { + NSDictionary<NSNumber *, MDCShadow *> *_shadowValuesForElevation; + NSArray<NSNumber *> *_orderedKeys; +} + +- (instancetype)initWithShadowValuesForElevation: + (NSDictionary<NSNumber *, MDCShadow *> *)shadowValuesForElevation { + self = [super init]; + if (self) { + _shadowValuesForElevation = [shadowValuesForElevation copy]; + _orderedKeys = [shadowValuesForElevation.allKeys sortedArrayUsingSelector:@selector(compare:)]; + } + return self; +} + +- (MDCShadow *)shadowForElevation:(CGFloat)elevation { + NSUInteger lookupIndex = [self indexInOrderedKeysOfGivenElevation:elevation]; + // If the value is larger than the largest value in the array, we will return the highest value in + // the array. + if (lookupIndex >= _orderedKeys.count) { + lookupIndex = _orderedKeys.count - 1; + } + + NSNumber *key = _orderedKeys[lookupIndex]; + return [_shadowValuesForElevation objectForKey:key]; +} + +- (NSUInteger)indexInOrderedKeysOfGivenElevation:(CGFloat)elevation { + NSNumber *num = @(elevation); + NSUInteger index = + [_orderedKeys indexOfObject:num + inSortedRange:NSMakeRange(0, _orderedKeys.count) + options:NSBinarySearchingInsertionIndex + usingComparator:^NSComparisonResult(NSNumber *num1, NSNumber *num2) { + return [num1 compare:num2]; + }]; + return index; +} + +@end + +@implementation MDCShadowsCollectionBuilder { + NSMutableDictionary<NSNumber *, MDCShadow *> *_shadowValuesForElevation; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _shadowValuesForElevation = [[NSMutableDictionary alloc] init]; + } + return self; +} + ++ (MDCShadowsCollectionBuilder *)builderWithShadow:(MDCShadow *)shadow + forElevation:(CGFloat)elevation { + MDCShadowsCollectionBuilder *builder = [[self alloc] init]; + [builder addShadow:shadow forElevation:elevation]; + return builder; +} + +- (void)addShadow:(MDCShadow *)shadow forElevation:(CGFloat)elevation { + [_shadowValuesForElevation setObject:shadow forKey:@(elevation)]; +} + +- (void)addShadowsForElevations:(NSDictionary<NSNumber *, MDCShadow *> *)shadowsForElevations { + [_shadowValuesForElevation addEntriesFromDictionary:shadowsForElevations]; +} + +- (MDCShadowsCollection *)build { + return [[MDCShadowsCollection alloc] initWithShadowValuesForElevation:_shadowValuesForElevation]; +} + +@end + +static UIColor *LightStyleShadowColor(void) { + static UIColor *lightStyleShadowColor; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lightStyleShadowColor = [UIColor colorWithRed:0.235 green:0.251 blue:0.263 alpha:1]; + }); + return lightStyleShadowColor; +} + +UIColor *MDCShadowColor(void) { +#if MDC_AVAILABLE_SDK_IOS(13_0) + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^(UITraitCollection *traitCollection) { + switch (traitCollection.userInterfaceStyle) { + case UIUserInterfaceStyleUnspecified: + /* FALLTHROUGH - TODO(b/185199658): Migrate to proper fallthrough logic */ + case UIUserInterfaceStyleLight: + return LightStyleShadowColor(); + case UIUserInterfaceStyleDark: + return UIColor.blackColor; + } + __builtin_unreachable(); + }]; + } +#endif // MDC_AVAILABLE_SDK_IOS(13_0) + return LightStyleShadowColor(); +} + +MDCShadowsCollection *MDCShadowsCollectionDefault(void) { + static MDCShadowsCollection *shadowsCollection; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + MDCShadow *shadow = [[MDCShadowBuilder builderWithOpacity:0 radius:0 + offset:CGSizeMake(0, 0)] build]; + MDCShadowsCollectionBuilder *shadowsBuilder = + [MDCShadowsCollectionBuilder builderWithShadow:shadow forElevation:0]; + NSDictionary<NSNumber *, MDCShadow *> *shadowValuesForElevation = @{ + @1 : [[MDCShadowBuilder builderWithOpacity:0.43 radius:2.5 offset:CGSizeMake(0, 1)] build], + @3 : [[MDCShadowBuilder builderWithOpacity:0.4 radius:3.25 offset:CGSizeMake(0, 1.25)] build], + @6 : [[MDCShadowBuilder builderWithOpacity:0.34 radius:4.75 + offset:CGSizeMake(0, 2.25)] build], + @8 : [[MDCShadowBuilder builderWithOpacity:0.42 radius:6 offset:CGSizeMake(0, 3)] build], + @12 : [[MDCShadowBuilder builderWithOpacity:0.4 radius:7.25 offset:CGSizeMake(0, 5)] build], + }; + [shadowsBuilder addShadowsForElevations:shadowValuesForElevation]; + shadowsCollection = [shadowsBuilder build]; + }); + return shadowsCollection; +} + +void MDCConfigureShadowForView(UIView *view, MDCShadow *shadow, UIColor *shadowColor) { + // The bezierPathWithRoundedRect API supports both a cornerRadius of 0 (created just a square + // path) and also rounded corners where the cornerRadius is >0. + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:view.bounds + cornerRadius:view.layer.cornerRadius]; + + MDCConfigureShadowForViewWithPath(view, shadow, shadowColor, path.CGPath); +} + +void MDCConfigureShadowForViewWithPath(UIView *view, MDCShadow *shadow, UIColor *shadowColor, + CGPathRef path) { +#if MDC_AVAILABLE_SDK_IOS(13_0) + if (@available(ios 13.0, *)) { + shadowColor = [shadowColor resolvedColorWithTraitCollection:view.traitCollection]; + } +#endif // MDC_AVAILABLE_SDK_IOS(13_0) + view.layer.shadowColor = shadowColor.CGColor; + view.layer.shadowOpacity = (float)shadow.opacity; + view.layer.shadowRadius = shadow.radius; + view.layer.shadowOffset = shadow.offset; + view.layer.shadowPath = path; +}
diff --git a/components/Shadow/src/MaterialShadow.h b/components/Shadow/src/MaterialShadow.h index c4fb107..c66cffe 100644 --- a/components/Shadow/src/MaterialShadow.h +++ b/components/Shadow/src/MaterialShadow.h
@@ -14,4 +14,4 @@ // limitations under the License. #import "MDCShadow.h" -#import "MDCShadowConfiguring.h" +#import "MDCShadowsCollection.h"
diff --git a/components/Shadow/tests/snapshot/MDCShadowSnapshotTests.m b/components/Shadow/tests/snapshot/MDCShadowSnapshotTests.m index 13c705e..03c0d47 100644 --- a/components/Shadow/tests/snapshot/MDCShadowSnapshotTests.m +++ b/components/Shadow/tests/snapshot/MDCShadowSnapshotTests.m
@@ -48,6 +48,7 @@ @property(nonatomic, strong, nullable) CAShapeLayer *shapeLayer; @property(nonatomic, nullable) CGPathRef shapePath; @property(nonatomic, strong, nullable) UITraitCollection *traitCollectionOverride; + @end @implementation MDCShadowTestView @@ -68,13 +69,17 @@ - (void)layoutSubviews { [super layoutSubviews]; - if (self.shapePath) { + if (self.shapePath != nil) { + _Nonnull CGPathRef shapePath = self.shapePath; self.backgroundColor = nil; - MDCShadow *shadow = MDCShadowForElevation(self.shadowElevation); - MDCConfigureShadowForViewWithShadowAndPath(self, self.shadowColor, shadow, self.shapePath); + MDCConfigureShadowForViewWithPath( + self, [MDCShadowsCollectionDefault() shadowForElevation:self.shadowElevation], + self.shadowColor, shapePath); } else { self.backgroundColor = UIColor.whiteColor; - MDCConfigureShadowForViewWithElevation(self, self.shadowColor, self.shadowElevation); + MDCConfigureShadowForView( + self, [MDCShadowsCollectionDefault() shadowForElevation:self.shadowElevation], + self.shadowColor); } } @@ -135,7 +140,7 @@ - (void)testShadowWithLowElevationShouldRenderShadow { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; // Then [self generateSnapshotAndVerifyForView:self.view]; @@ -143,7 +148,7 @@ - (void)testShadowWithHighElevationShouldRenderShadow { // Given - self.view.shadowElevation = 10; + self.view.shadowElevation = 8; // Then [self generateSnapshotAndVerifyForView:self.view]; @@ -151,7 +156,7 @@ - (void)testShadowWithLowElevationShouldUpdateShadowOnBoundsChange { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; // When [self.view layoutIfNeeded]; @@ -163,7 +168,7 @@ - (void)testShadowWithLowElevationAndCornerRadiusShouldRenderRoundedShadow { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; self.view.layer.cornerRadius = 3; // Then @@ -172,7 +177,7 @@ - (void)testShadowWithLowElevationAndCornerRadiusShouldUpdateShadowOnBoundsChange { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; self.view.layer.cornerRadius = 3; // When @@ -185,7 +190,7 @@ - (void)testShadowWithLowElevationAndShapeLayerShouldRenderShapedShadow { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; UIBezierPath *triangleBezierPath = UIBezierPath.bezierPath; [triangleBezierPath moveToPoint:CGPointMake(40, 0)]; [triangleBezierPath addLineToPoint:CGPointMake(80, 80)]; @@ -201,7 +206,7 @@ #if MDC_AVAILABLE_SDK_IOS(13_0) if (@available(iOS 13.0, *)) { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; self.view.shadowColor = MDCTestDynamicShadowColor(); // When @@ -218,7 +223,7 @@ #if MDC_AVAILABLE_SDK_IOS(13_0) if (@available(iOS 13.0, *)) { // Given - self.view.shadowElevation = 2; + self.view.shadowElevation = 1; self.view.shadowColor = MDCTestDynamicShadowColor(); // When
diff --git a/components/Shadow/tests/unit/MDCShadowTests.m b/components/Shadow/tests/unit/MDCShadowTests.m index 68b7152..dcd0448 100644 --- a/components/Shadow/tests/unit/MDCShadowTests.m +++ b/components/Shadow/tests/unit/MDCShadowTests.m
@@ -14,7 +14,11 @@ #import <XCTest/XCTest.h> -#import "MDCShadow.h" +#import "MaterialShadow.h" + +@interface MDCShadowsCollection (Testing) +- (MDCShadow *)shadowForElevation:(CGFloat)elevation; +@end @interface MDCShadowTests : XCTestCase @end @@ -23,7 +27,7 @@ - (void)testZeroElevationShouldReturnEmptyShadow { // Given - MDCShadow *shadow = MDCShadowForElevation(0); + MDCShadow *shadow = [MDCShadowsCollectionDefault() shadowForElevation:0]; // Then XCTAssertEqual(shadow.opacity, 0); @@ -33,7 +37,7 @@ - (void)testLowElevationShouldReturnShadow { // Given - MDCShadow *shadow = MDCShadowForElevation(2); + MDCShadow *shadow = [MDCShadowsCollectionDefault() shadowForElevation:2]; // Then XCTAssertGreaterThan(shadow.opacity, 0); @@ -43,7 +47,7 @@ - (void)testHighElevationShouldReturnShadow { // Given - MDCShadow *shadow = MDCShadowForElevation(24); + MDCShadow *shadow = [MDCShadowsCollectionDefault() shadowForElevation:24]; // Then XCTAssertGreaterThan(shadow.opacity, 0); @@ -53,8 +57,8 @@ - (void)testSameElevationShouldBeEqualToSelf { // Given - MDCShadow *lowElevationShadowA = MDCShadowForElevation(2); - MDCShadow *lowElevationShadowB = MDCShadowForElevation(2); + MDCShadow *lowElevationShadowA = [MDCShadowsCollectionDefault() shadowForElevation:2]; + MDCShadow *lowElevationShadowB = [MDCShadowsCollectionDefault() shadowForElevation:2]; // Then XCTAssertEqualObjects(lowElevationShadowA, lowElevationShadowB); @@ -62,29 +66,60 @@ - (void)testLowElevationShouldReturnDifferentShadowFromHighElevation { // Given - MDCShadow *lowElevationShadow = MDCShadowForElevation(2); - MDCShadow *highElevationShadow = MDCShadowForElevation(24); + MDCShadow *lowElevationShadow = [MDCShadowsCollectionDefault() shadowForElevation:2]; + MDCShadow *highElevationShadow = [MDCShadowsCollectionDefault() shadowForElevation:24]; // Then XCTAssertNotEqualObjects(lowElevationShadow, highElevationShadow); } -- (void)testBuilderReturnsExpectedValues { +- (void)testDefaultShadowElevationValuesAreReturnedCorrectlyForOutOfBoundsElevations { // Given - MDCShadowBuilder *shadowBuilder = [[MDCShadowBuilder alloc] init]; + MDCShadowsCollection *shadowsCollection = MDCShadowsCollectionDefault(); // When - shadowBuilder.opacity = 42; - shadowBuilder.radius = 23; - shadowBuilder.offset = CGSizeMake(1, 2); - - MDCShadow *shadow = [shadowBuilder build]; + MDCShadow *negativeShadow = [shadowsCollection shadowForElevation:-4]; + MDCShadow *bigShadow = [shadowsCollection shadowForElevation:13]; + MDCShadow *hugeShadow = [shadowsCollection shadowForElevation:3000]; // Then - XCTAssertEqualWithAccuracy(shadow.opacity, 42, 1e-6); - XCTAssertEqualWithAccuracy(shadow.radius, 23, 1e-6); - XCTAssertEqualWithAccuracy(shadow.offset.width, 1, 1e-6); - XCTAssertEqualWithAccuracy(shadow.offset.height, 2, 1e-6); + XCTAssertEqualObjects(negativeShadow, [shadowsCollection shadowForElevation:0]); + XCTAssertEqualObjects(bigShadow, [shadowsCollection shadowForElevation:12]); + XCTAssertEqualObjects(hugeShadow, [shadowsCollection shadowForElevation:12]); +} + +- (void)testDefaultShadowElevationValuesAreReturnedCorrectlyForInBetweenValueElevations { + // Given + MDCShadowsCollection *shadowsCollection = MDCShadowsCollectionDefault(); + + // When + MDCShadow *shadow1 = [shadowsCollection shadowForElevation:0.1]; + MDCShadow *shadow2 = [shadowsCollection shadowForElevation:2.314]; + MDCShadow *shadow3 = [shadowsCollection shadowForElevation:4]; + MDCShadow *shadow4 = [shadowsCollection shadowForElevation:6.01]; + MDCShadow *shadow5 = [shadowsCollection shadowForElevation:9.11]; + + // Then + XCTAssertEqualObjects(shadow1, [shadowsCollection shadowForElevation:1]); + XCTAssertEqualObjects(shadow2, [shadowsCollection shadowForElevation:3]); + XCTAssertEqualObjects(shadow3, [shadowsCollection shadowForElevation:6]); + XCTAssertEqualObjects(shadow4, [shadowsCollection shadowForElevation:8]); + XCTAssertEqualObjects(shadow5, [shadowsCollection shadowForElevation:12]); +} + +- (void)testSettingNewShadowInstanceUsingBuilder { + // Given + MDCShadow *shadow = [[MDCShadowBuilder builderWithOpacity:0.1 + radius:0.2 + offset:CGSizeMake(0.3, 0.4)] build]; + + // When + MDCShadowsCollection *shadowsCollection = + [[MDCShadowsCollectionBuilder builderWithShadow:shadow forElevation:4] build]; + + // Then + MDCShadow *fetchedShadow = [shadowsCollection shadowForElevation:4]; + XCTAssertEqualObjects(shadow, fetchedShadow); } @end
diff --git a/components/ShadowElevations/README.md b/components/ShadowElevations/README.md index 1ccc4ba..3fd5d50 100644 --- a/components/ShadowElevations/README.md +++ b/components/ShadowElevations/README.md
@@ -15,9 +15,7 @@ surface resulting in a more prominent, albeit more diffuse, shadow. This component provides commonly used Material Design elevations for components. -<div class="article__asset article__asset--screenshot"> - <img src="docs/assets/shadows.png" alt="Shadows" width="375"> -</div> +<img src="docs/assets/shadows.png" alt="Shadows" width="375"> ## Design & API Documentation
diff --git a/components/Shapes/src/MDCShapeMediator.h b/components/Shapes/src/MDCShapeMediator.h new file mode 100644 index 0000000..3768547 --- /dev/null +++ b/components/Shapes/src/MDCShapeMediator.h
@@ -0,0 +1,116 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 <QuartzCore/QuartzCore.h> +#import <UIKit/UIKit.h> + +@protocol MDCShapeGenerating; + +/* + Shape support addition to a layer. + + This class is used to add Shape support to a given view by providing it with the view's main layer. + Having shape support means that by setting a shapeGenerator, you are able to have a custom shape + using a custom path for that view. + + To have your instantiating view's backgroundColor, borderColor, and borderWidth also follow the + custom shape, your view must have these APIs internally set and get from MDCShapeMediator's + corresponding shapedBackgroundColor, shapedBorderColor, and shapedBorderWidth properties. + + This class exists to supersede MDCShapedShadowLayer which previously added shape support by + overriding the layerClass and subclassing MDCShadowLayer, which are both behaviors we want to no + longer support due to their complexity and constraints. + */ +__attribute__((objc_subclassing_restricted)) @interface MDCShapeMediator : NSObject + +- (nonnull instancetype)init NS_UNAVAILABLE; + +/** + Designated initializer for a view requiring shape support to initialize with the view’s Core + Animation layer used for rendering (view.layer). + + The MDCShapeMediator class then keeps a weak reference to the layer and adds the required sublayers + in order to support custom shapes using custom paths. It also updates the layer's properties to + have the border and background properties as well as its shadow path be up to date with the shape's + custom path it gets through the shapeGenerator API. + */ +- (nonnull instancetype)initWithViewLayer:(nonnull CALayer *)viewLayer NS_DESIGNATED_INITIALIZER; + +/** + Call this function in layoutSubviews of the viewLayer's view to allow the shape generator to + generate the proper shape path when the bounds are now apparent. + */ +- (void)layoutShapedSublayers; + +/** + The layer which the shape logic sits on. Assign the parent layer using @c initWithLayer: + */ +@property(nonatomic, readonly, weak, nullable) CALayer *viewLayer; + +/* + Sets the shaped background color of the layer. + + Use shapedBackgroundColor instead of backgroundColor to ensure the background appears correct with + or without a valid shape. + + @note If you set shapedBackgroundColor, you should not manually write to backgroundColor or + fillColor. + */ +@property(nonatomic, copy, nullable) UIColor *shapedBackgroundColor; + +/* + Sets the shaped border color of the layer. + + Use shapedBorderColor instead of borderColor to ensure the border appears correct with or without + a valid shape. + + @note If you set shapedBorderColor, you should not manually write to borderColor. + */ +@property(nonatomic, copy, nullable) UIColor *shapedBorderColor; + +/* + Sets the shaped border width of the layer. + + Use shapedBorderWidth instead of borderWidth to ensure the border appears correct with or without + a valid shape. + + @note If you set shapedBorderWidth, you should not manually write to borderWidth. + */ +@property(nonatomic, assign) CGFloat shapedBorderWidth; + +/* + The MDCShapeGenerating object used to set the shape's path and shadow path. + + The path will be set upon assignment of this property and whenever layoutSublayers is called. + */ +@property(nonatomic, strong, nullable) id<MDCShapeGenerating> shapeGenerator; + +/* + The created CAShapeLayer representing the generated shape path for the implementing UIView + from the shapeGenerator. + + This layer is exposed to easily mask subviews of the implementing UIView so they won't spill + outside the layer to fit the bounds. + */ +@property(nonatomic, strong, nonnull) CAShapeLayer *shapeLayer; + +/* + A sublayer of @c shapeLayer that is responsible for the background color of the shape layer. + + The colorLayer imitates the path of shapeLayer and is added as a sublayer. It is updated when + shapedBackgroundColor is set on the layer. + */ +@property(nonatomic, strong, nonnull) CAShapeLayer *colorLayer; + +@end
diff --git a/components/Shapes/src/MDCShapeMediator.m b/components/Shapes/src/MDCShapeMediator.m new file mode 100644 index 0000000..b057bb3 --- /dev/null +++ b/components/Shapes/src/MDCShapeMediator.m
@@ -0,0 +1,197 @@ +// Copyright 2021-present the Material Components for iOS authors. 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 "MDCShapeMediator.h" + +#import "MDCShapeGenerating.h" +#import "MaterialColor.h" + +// An epsilon for use with width/height values. +static const CGFloat kDimensionalEpsilon = 0.001; + +@implementation MDCShapeMediator + +- (instancetype)initWithViewLayer:(CALayer *)viewLayer { + self = [super init]; + if (self) { + _viewLayer = viewLayer; + _viewLayer.backgroundColor = [UIColor clearColor].CGColor; + _colorLayer = [CAShapeLayer layer]; + _colorLayer.delegate = (id<CALayerDelegate>)_viewLayer; + _shapeLayer = [CAShapeLayer layer]; + [_viewLayer insertSublayer:_colorLayer atIndex:0]; + } + return self; +} + +- (void)layoutShapedSublayers { + CGRect bounds = _viewLayer.bounds; + + CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); + _colorLayer.position = center; + _colorLayer.bounds = bounds; + + [self prepareShadowPath]; +} + +- (void)prepareShadowPath { + if (self.shapeGenerator) { + CGRect standardizedBounds = CGRectStandardize(_viewLayer.bounds); + self.path = [self.shapeGenerator pathForSize:standardizedBounds.size]; + } +} + +- (void)setShapeGenerator:(id<MDCShapeGenerating>)shapeGenerator { + _shapeGenerator = shapeGenerator; + + CGRect standardizedBounds = CGRectStandardize(_viewLayer.bounds); + self.path = [self.shapeGenerator pathForSize:standardizedBounds.size]; +} + +- (void)setPath:(CGPathRef)path { + _viewLayer.shadowPath = path; + _colorLayer.path = path; + _shapeLayer.path = path; + + if (CGPathIsEmpty(path)) { + _viewLayer.backgroundColor = self.shapedBackgroundColor.CGColor; + _viewLayer.borderColor = self.shapedBorderColor.CGColor; + _viewLayer.borderWidth = self.shapedBorderWidth; + + _colorLayer.fillColor = nil; + _colorLayer.strokeColor = nil; + _colorLayer.lineWidth = 0; + } else { + _viewLayer.backgroundColor = nil; + _viewLayer.borderColor = nil; + _viewLayer.borderWidth = 0; + + _colorLayer.fillColor = self.shapedBackgroundColor.CGColor; + _colorLayer.strokeColor = self.shapedBorderColor.CGColor; + _colorLayer.lineWidth = self.shapedBorderWidth; + [self generateColorPathGivenLineWidth]; + } +} + +- (void)generateColorPathGivenLineWidth { + if (CGPathIsEmpty(self.path) || _colorLayer.lineWidth <= 0) { + _colorLayer.path = _viewLayer.shadowPath; + _shapeLayer.path = _viewLayer.shadowPath; + return; + } + CGFloat halfOfBorderWidth = self.shapedBorderWidth / 2.f; + CGAffineTransform colorLayerTransform = [self generateTransformInsetByValue:halfOfBorderWidth]; + CGPathRef colorLayerPath = + CGPathCreateCopyByTransformingPath(_viewLayer.shadowPath, &colorLayerTransform); + _colorLayer.path = colorLayerPath; + CGPathRelease(colorLayerPath); + // The shape layer is used to provide the user a mask for their content, which means also + // show the full border. Because the border is shown half outside and half inside + // the color layer path, we must inset the shape layer by the full border width. + CGAffineTransform shapeLayerTransform = + [self generateTransformInsetByValue:self.shapedBorderWidth]; + CGPathRef shapeLayerPath = + CGPathCreateCopyByTransformingPath(_viewLayer.shadowPath, &shapeLayerTransform); + _shapeLayer.path = shapeLayerPath; + CGPathRelease(shapeLayerPath); +} + +- (CGAffineTransform)generateTransformInsetByValue:(CGFloat)value { + // Use the identitfy transfrom when inset is less than Epsilon. + if (value < kDimensionalEpsilon) { + return CGAffineTransformIdentity; + } + + // Use the path's boundingBox to get the proportion of inset value, + // because this tranform is expected to be applied on a CGPath. + CGRect pathBoundingBox = CGPathGetPathBoundingBox(_viewLayer.shadowPath); + CGRect pathStandardizedBounds = CGRectStandardize(pathBoundingBox); + + if (CGRectGetWidth(pathStandardizedBounds) < kDimensionalEpsilon || + CGRectGetHeight(pathStandardizedBounds) < kDimensionalEpsilon) { + return CGAffineTransformIdentity; + } + + CGRect insetBounds = CGRectInset(pathStandardizedBounds, value, value); + CGFloat width = CGRectGetWidth(pathStandardizedBounds); + CGFloat height = CGRectGetHeight(pathStandardizedBounds); + CGFloat pathCenterX = CGRectGetMidX(pathStandardizedBounds); + CGFloat pathCenterY = CGRectGetMidY(pathStandardizedBounds); + // Calculate the shifted center and re-center it by applying a translation transform. + // value * 2 represents the accumulated borderWidth on each side, value * 2 / width + // represents the proportion of accumulated borderWidth in path bounds, which is also + // the value used for scale transform. + // The shiftWidth represents the shifted length horizontally on the center. + CGFloat shiftWidth = value * 2 / width * pathCenterX; + // Same calculation for height. + CGFloat shiftHeight = value * 2 / height * pathCenterY; + CGAffineTransform transform = CGAffineTransformMakeTranslation(shiftWidth, shiftHeight); + transform = CGAffineTransformScale(transform, CGRectGetWidth(insetBounds) / width, + CGRectGetHeight(insetBounds) / height); + return transform; +} + +- (CGPathRef)path { + return _colorLayer.path; +} + +- (void)setShapedBackgroundColor:(UIColor *)shapedBackgroundColor { + _shapedBackgroundColor = shapedBackgroundColor; + + if ([_viewLayer.delegate isKindOfClass:[UIView class]]) { + UIView *view = (UIView *)_viewLayer.delegate; + _shapedBackgroundColor = + [_shapedBackgroundColor mdc_resolvedColorWithTraitCollection:view.traitCollection]; + } + + if (CGPathIsEmpty(self.path)) { + _viewLayer.backgroundColor = _shapedBackgroundColor.CGColor; + _colorLayer.fillColor = nil; + } else { + _viewLayer.backgroundColor = nil; + _colorLayer.fillColor = _shapedBackgroundColor.CGColor; + } +} + +- (void)setShapedBorderColor:(UIColor *)shapedBorderColor { + _shapedBorderColor = shapedBorderColor; + + if ([_viewLayer.delegate isKindOfClass:[UIView class]]) { + UIView *view = (UIView *)_viewLayer.delegate; + _shapedBorderColor = + [_shapedBorderColor mdc_resolvedColorWithTraitCollection:view.traitCollection]; + } + if (CGPathIsEmpty(self.path)) { + _viewLayer.borderColor = _shapedBorderColor.CGColor; + _colorLayer.strokeColor = nil; + } else { + _viewLayer.borderColor = nil; + _colorLayer.strokeColor = _shapedBorderColor.CGColor; + } +} + +- (void)setShapedBorderWidth:(CGFloat)shapedBorderWidth { + _shapedBorderWidth = shapedBorderWidth; + + if (CGPathIsEmpty(self.path)) { + _viewLayer.borderWidth = _shapedBorderWidth; + _colorLayer.lineWidth = 0; + } else { + _viewLayer.borderWidth = 0; + _colorLayer.lineWidth = _shapedBorderWidth; + [self generateColorPathGivenLineWidth]; + } +} + +@end
diff --git a/components/Shapes/src/MaterialShapes.h b/components/Shapes/src/MaterialShapes.h index 0220fa8..c68ff07 100644 --- a/components/Shapes/src/MaterialShapes.h +++ b/components/Shapes/src/MaterialShapes.h
@@ -17,5 +17,6 @@ #import "MDCPathGenerator.h" #import "MDCRectangleShapeGenerator.h" #import "MDCShapeGenerating.h" +#import "MDCShapeMediator.h" #import "MDCShapedShadowLayer.h" #import "MDCShapedView.h"
diff --git a/components/Shapes/tests/unit/MDCShapeMediatorTests.m b/components/Shapes/tests/unit/MDCShapeMediatorTests.m new file mode 100644 index 0000000..6dee568 --- /dev/null +++ b/components/Shapes/tests/unit/MDCShapeMediatorTests.m
@@ -0,0 +1,131 @@ +#import "MaterialShapeLibrary.h" +#import "MaterialShapes.h" + +#import <XCTest/XCTest.h> + +@interface MDCShapeMediator (UnitTesting) + +- (void)setPath:(CGPathRef)path; +- (CGPathRef)path; + +@end + +@interface MDCShapeMediatorTests : XCTestCase +@end + +@implementation MDCShapeMediatorTests + +- (void)testViewsLayerIsShapeMediatorsViewLayer { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + + // Then + XCTAssertEqualObjects(view.layer, shapeMediator.viewLayer); +} + +- (void)testSettingShapedBackgroundColorSetsViewsBackgroundColor { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + + // When + shapeMediator.shapedBackgroundColor = UIColor.blueColor; + + // Then + XCTAssertEqualObjects(view.backgroundColor, UIColor.blueColor); +} + +- (void)testSettingShapedBorderColorSetsViewsBorderColor { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + + // When + shapeMediator.shapedBorderColor = UIColor.blueColor; + + // Then + XCTAssertTrue(CGColorEqualToColor(view.layer.borderColor, UIColor.blueColor.CGColor)); +} + +- (void)testSettingShapedBorderWithSetsViewsBorderWidth { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + + // When + shapeMediator.shapedBorderWidth = 3.4f; + + // Then + XCTAssertEqual(view.layer.borderWidth, 3.4f); +} + +- (void)testEmptyFrameWithNonEmptyPathGeneratesColorLayerPathMatchingPath { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)]; + + // When + shapeMediator.viewLayer.frame = CGRectZero; + shapeMediator.path = bezierPath.CGPath; + + // Then + XCTAssertTrue(CGPathEqualToPath(shapeMediator.colorLayer.path, bezierPath.CGPath)); +} + +- (void) + testEmptyFrameWithNonEmptyPathAndPositiveShapedBorderWidthGeneratesColorLayerPathOffsetByHalfOfLineWidth { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)]; + + // When + shapeMediator.viewLayer.frame = CGRectZero; + shapeMediator.shapedBorderWidth = 2; + shapeMediator.path = bezierPath.CGPath; + + // Then + // Note that the X and Y values here are shifted by half of the shaped border width. + UIBezierPath *insetPath = [UIBezierPath bezierPathWithRect:CGRectMake(1, 1, 98, 98)]; + XCTAssertTrue(CGPathEqualToPath(shapeMediator.colorLayer.path, insetPath.CGPath)); +} + +- (void)testGeneratedColorLayerAndShapeLayerPathsGivenABorderAndShadowLayer { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)]; + + // When + shapeMediator.viewLayer.frame = CGRectMake(0, 0, 100, 100); + shapeMediator.shapedBorderWidth = 6; + shapeMediator.path = bezierPath.CGPath; + + // Then + UIBezierPath *halfInsetPath = [UIBezierPath bezierPathWithRect:CGRectMake(3, 3, 94, 94)]; + XCTAssertTrue(CGPathEqualToPath(shapeMediator.colorLayer.path, halfInsetPath.CGPath)); + UIBezierPath *fullInsetPath = [UIBezierPath bezierPathWithRect:CGRectMake(6, 6, 88, 88)]; + XCTAssertTrue(CGPathEqualToPath(shapeMediator.shapeLayer.path, fullInsetPath.CGPath)); +} + +- (void)testSettingShapeGeneratorProvidesCustomPathsToShadowPathAndShapeLayerAndColorLayer { + // Given + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + MDCShapeMediator *shapeMediator = [[MDCShapeMediator alloc] initWithViewLayer:view.layer]; + + // When + MDCRectangleShapeGenerator *shapeGenerator = [[MDCRectangleShapeGenerator alloc] init]; + MDCRoundedCornerTreatment *cornerTreatment = [MDCRoundedCornerTreatment cornerWithRadius:10]; + [shapeGenerator setCorners:cornerTreatment]; + shapeMediator.shapeGenerator = shapeGenerator; + + // Then + XCTAssertFalse(CGPathIsEmpty(shapeMediator.path)); + XCTAssertFalse(CGPathIsEmpty(shapeMediator.colorLayer.path)); + XCTAssertFalse(CGPathIsEmpty(shapeMediator.shapeLayer.path)); + XCTAssertFalse(CGPathIsEmpty(view.layer.shadowPath)); +} + +@end
diff --git a/components/SideSheet/.jazzy.yaml b/components/SideSheet/.jazzy.yaml deleted file mode 100644 index afe8156..0000000 --- a/components/SideSheet/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: SideSheet -umbrella_header: src/MaterialSideSheet.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/SideSheet/README.md b/components/SideSheet/README.md deleted file mode 100644 index 932b525..0000000 --- a/components/SideSheet/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -# Side Sheet - -The [Side Sheet component](https://material.io/go/design-sheets-side) is yet to be completed, please follow the [tracking issue](https://www.pivotaltracker.com/epic/show/3950597) for more information. -
diff --git a/components/Slider/README.md b/components/Slider/README.md index 87d1a9c..5f0bed7 100644 --- a/components/Slider/README.md +++ b/components/Slider/README.md
@@ -16,7 +16,7 @@  -## Contents +**Contents** * [Using sliders](#using-sliders) * [Continuous sliders](#continuous-sliders) @@ -132,6 +132,7 @@ Set an appropriate `accessibilityLabel` value for your slider. This should reflect what the slider affects. +<!--<div class="material-code-render" markdown="1">--> #### Swift ```swift slider.accessibilityLabel = "Volume level" @@ -141,6 +142,7 @@ ```objc slider.accessibilityLabel = @"Volume level"; ``` +<!--</div>--> #### Minimum touch size @@ -149,7 +151,7 @@ The height of the slider is set to 27 points so make sure there is sufficient space so that touches don't affect other elements. -## Types +**Types** There are two types of sliders: 1\. [Continuous slider](#continuous-slider) and 2\. [Discrete slider](#discrete-slider) @@ -158,6 +160,8 @@ A slider with one thumb is called a single point slider, and a slider with two thumbs is called a range slider. +_**Note:** Range sliders are not supported on iOS._ + ### Anatomy and key properties A slider has a track, one or two thumbs, and optional value label. A discrete @@ -240,10 +244,6 @@ ``` <!--</div>--> -#### Continuous range slider example - -Range sliders are not yet implemented on iOS. - ## Discrete sliders #### Discrete single point slider example @@ -278,10 +278,6 @@ ``` <!--</div>--> -#### Discrete range slider example - -Range sliders are not yet implemented on iOS. - ## Theming sliders `MDCSlider` has no recommended theming mechanism. Configure colors using the properties and stateful APIs exposed on the slider.
diff --git a/components/Snackbar/README.md b/components/Snackbar/README.md index 9937a0b..523645f 100644 --- a/components/Snackbar/README.md +++ b/components/Snackbar/README.md
@@ -78,10 +78,6 @@ messages are suspended. When the client releases the suspension token or calls the manager's resume method with the suspension token, then messages will resume being displayed. -## Types - -There is only one type of snackbar. - ## Snackbar 
diff --git a/components/Snackbar/tests/unit/supplemental/MDCFakeMDCSnackbarManagerDelegate.h b/components/Snackbar/tests/unit/MDCFakeMDCSnackbarManagerDelegate.h similarity index 100% rename from components/Snackbar/tests/unit/supplemental/MDCFakeMDCSnackbarManagerDelegate.h rename to components/Snackbar/tests/unit/MDCFakeMDCSnackbarManagerDelegate.h
diff --git a/components/Snackbar/tests/unit/supplemental/MDCFakeMDCSnackbarManagerDelegate.m b/components/Snackbar/tests/unit/MDCFakeMDCSnackbarManagerDelegate.m similarity index 97% rename from components/Snackbar/tests/unit/supplemental/MDCFakeMDCSnackbarManagerDelegate.m rename to components/Snackbar/tests/unit/MDCFakeMDCSnackbarManagerDelegate.m index 8f3fc58..b709427 100644 --- a/components/Snackbar/tests/unit/supplemental/MDCFakeMDCSnackbarManagerDelegate.m +++ b/components/Snackbar/tests/unit/MDCFakeMDCSnackbarManagerDelegate.m
@@ -14,6 +14,8 @@ #import "MDCFakeMDCSnackbarManagerDelegate.h" +#import "MaterialSnackbar.h" + @implementation FakeMDCSnackbarManagerDelegate - (void)willPresentSnackbarWithMessageView:(MDCSnackbarMessageView *)messageView {
diff --git a/components/Snackbar/tests/unit/MDCSnackbarManagerInstanceTests.m b/components/Snackbar/tests/unit/MDCSnackbarManagerInstanceTests.m index 7c519e1..9d1fa57 100644 --- a/components/Snackbar/tests/unit/MDCSnackbarManagerInstanceTests.m +++ b/components/Snackbar/tests/unit/MDCSnackbarManagerInstanceTests.m
@@ -15,7 +15,7 @@ #import <XCTest/XCTest.h> #import "MaterialSnackbar.h" -#import "supplemental/MDCFakeMDCSnackbarManagerDelegate.h" +#import "MDCFakeMDCSnackbarManagerDelegate.h" @interface MDCSnackbarManagerInstanceTests : XCTestCase
diff --git a/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m b/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m index 1196aa2..4ebb09e 100644 --- a/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m +++ b/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m
@@ -14,10 +14,10 @@ #import <XCTest/XCTest.h> -#import "supplemental/MDCFakeMDCSnackbarManagerDelegate.h" #import "MaterialButtons.h" #import "MaterialShadowElevations.h" #import "MaterialSnackbar.h" +#import "MDCFakeMDCSnackbarManagerDelegate.h" #import "MaterialTypography.h" #import "../../src/private/MDCSnackbarManagerInternal.h" @@ -442,69 +442,65 @@ } - (void)testMessageViewMessageDynamicTypeBehavior { - if (@available(iOS 10.0, *)) { - // Given - MDCSnackbarMessageViewTestsFakeView *messageView = - [[MDCSnackbarMessageViewTestsFakeView alloc] init]; - messageView.mdc_adjustsFontForContentSizeCategory = YES; + // Given + MDCSnackbarMessageViewTestsFakeView *messageView = + [[MDCSnackbarMessageViewTestsFakeView alloc] init]; + messageView.mdc_adjustsFontForContentSizeCategory = YES; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - messageView.adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = NO; + messageView.adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = NO; #pragma clang diagnostic pop - UIFont *messageFont = [UIFont systemFontOfSize:15.0 weight:UIFontWeightMedium]; - MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleBody1]; - messageFont = [fontScaler scaledFontWithFont:messageFont]; - messageFont = [messageFont mdc_scaledFontAtDefaultSize]; - messageView.messageFont = messageFont; - CGFloat originalMessageFontSize = messageView.label.font.pointSize; + UIFont *messageFont = [UIFont systemFontOfSize:15.0 weight:UIFontWeightMedium]; + MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleBody1]; + messageFont = [fontScaler scaledFontWithFont:messageFont]; + messageFont = [messageFont mdc_scaledFontAtDefaultSize]; + messageView.messageFont = messageFont; + CGFloat originalMessageFontSize = messageView.label.font.pointSize; - // When - UIContentSizeCategory size = UIContentSizeCategoryExtraExtraExtraLarge; - UITraitCollection *traitCollection = - [UITraitCollection traitCollectionWithPreferredContentSizeCategory:size]; - messageView.traitCollectionOverride = traitCollection; - [NSNotificationCenter.defaultCenter - postNotificationName:UIContentSizeCategoryDidChangeNotification - object:nil]; + // When + UIContentSizeCategory size = UIContentSizeCategoryExtraExtraExtraLarge; + UITraitCollection *traitCollection = + [UITraitCollection traitCollectionWithPreferredContentSizeCategory:size]; + messageView.traitCollectionOverride = traitCollection; + [NSNotificationCenter.defaultCenter + postNotificationName:UIContentSizeCategoryDidChangeNotification + object:nil]; - // Then - CGFloat actualMessageFontSize = messageView.label.font.pointSize; - XCTAssertGreaterThan(actualMessageFontSize, originalMessageFontSize); - } + // Then + CGFloat actualMessageFontSize = messageView.label.font.pointSize; + XCTAssertGreaterThan(actualMessageFontSize, originalMessageFontSize); } - (void)testMessageViewButtonDynamicTypeBehavior { - if (@available(iOS 10.0, *)) { - // Given - MDCSnackbarMessageViewTestsFakeView *messageView = - [[MDCSnackbarMessageViewTestsFakeView alloc] init]; - messageView.mdc_adjustsFontForContentSizeCategory = YES; + // Given + MDCSnackbarMessageViewTestsFakeView *messageView = + [[MDCSnackbarMessageViewTestsFakeView alloc] init]; + messageView.mdc_adjustsFontForContentSizeCategory = YES; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - messageView.adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = NO; + messageView.adjustsFontForContentSizeCategoryWhenScaledFontIsUnavailable = NO; #pragma clang diagnostic pop - MDCButton *button = [[MDCButton alloc] init]; - [messageView.actionButtons addObject:button]; - UIFont *buttonFont = [UIFont systemFontOfSize:10.0 weight:UIFontWeightMedium]; - MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleButton]; - buttonFont = [fontScaler scaledFontWithFont:buttonFont]; - buttonFont = [buttonFont mdc_scaledFontAtDefaultSize]; - messageView.buttonFont = buttonFont; - CGFloat originalButtonFontSize = [button titleFontForState:UIControlStateNormal].pointSize; + MDCButton *button = [[MDCButton alloc] init]; + [messageView.actionButtons addObject:button]; + UIFont *buttonFont = [UIFont systemFontOfSize:10.0 weight:UIFontWeightMedium]; + MDCFontScaler *fontScaler = [[MDCFontScaler alloc] initForMaterialTextStyle:MDCTextStyleButton]; + buttonFont = [fontScaler scaledFontWithFont:buttonFont]; + buttonFont = [buttonFont mdc_scaledFontAtDefaultSize]; + messageView.buttonFont = buttonFont; + CGFloat originalButtonFontSize = [button titleFontForState:UIControlStateNormal].pointSize; - // When - UIContentSizeCategory size = UIContentSizeCategoryExtraExtraExtraLarge; - UITraitCollection *traitCollection = - [UITraitCollection traitCollectionWithPreferredContentSizeCategory:size]; - messageView.traitCollectionOverride = traitCollection; - [NSNotificationCenter.defaultCenter - postNotificationName:UIContentSizeCategoryDidChangeNotification - object:nil]; + // When + UIContentSizeCategory size = UIContentSizeCategoryExtraExtraExtraLarge; + UITraitCollection *traitCollection = + [UITraitCollection traitCollectionWithPreferredContentSizeCategory:size]; + messageView.traitCollectionOverride = traitCollection; + [NSNotificationCenter.defaultCenter + postNotificationName:UIContentSizeCategoryDidChangeNotification + object:nil]; - // Then - CGFloat actualButtonFontSize = [button titleFontForState:UIControlStateNormal].pointSize; - XCTAssertGreaterThan(actualButtonFontSize, originalButtonFontSize); - } + // Then + CGFloat actualButtonFontSize = [button titleFontForState:UIControlStateNormal].pointSize; + XCTAssertGreaterThan(actualButtonFontSize, originalButtonFontSize); } - (void)testMessageViewAdjustsFontForContentSizeCategoryWhenScaledFontIsUnavailableDefaultValue { @@ -692,6 +688,8 @@ } - (void)testLegacySnackbarMessagePresentsThenDismisses { + // TODO(b/184189330): Evaluate why this is flaking. + // Given MDCSnackbarMessage.usesLegacySnackbar = YES; self.message.duration = 0.1;
diff --git a/components/Snackbar/tests/unit/SnackbarManagerTests.m b/components/Snackbar/tests/unit/SnackbarManagerTests.m index cb44967..552d988 100644 --- a/components/Snackbar/tests/unit/SnackbarManagerTests.m +++ b/components/Snackbar/tests/unit/SnackbarManagerTests.m
@@ -254,8 +254,17 @@ } - (void)testDefaultValueForOverrideBaseElevationIsNegative { + // TODO(b/184189330): Evaluate why this is flaking. + XCTSkip("b/184189330"); + // Then - XCTAssertLessThan(MDCSnackbarManager.defaultManager.mdc_overrideBaseElevation, 0); + if (@available(iOS 12, *)) { + XCTAssertEqualWithAccuracy(MDCSnackbarManager.defaultManager.mdc_overrideBaseElevation, 99, + FLT_EPSILON); + } else { + // TODO(b/184189330): Evaluate why this randomly oscillates between 99 and 0. + XCTAssertLessThan(MDCSnackbarManager.defaultManager.mdc_overrideBaseElevation, 0); + } } - (void)testDefaultValueForFocusedSnackbarsAccessibilityNotification {
diff --git a/components/Switch/.jazzy.yaml b/components/Switch/.jazzy.yaml deleted file mode 100644 index 803a126..0000000 --- a/components/Switch/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: Switch -umbrella_header: src/MaterialSwitch.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/Switch/README.md b/components/Switch/README.md deleted file mode 100644 index b26521e..0000000 --- a/components/Switch/README.md +++ /dev/null
@@ -1,3 +0,0 @@ -# Switch - -The [Switch component](https://material.io/go/design-switches) will not be implemented on iOS and [apps should use the native UISwitch instead](https://material.io/design/platform-guidance/cross-platform-adaptation.html).
diff --git a/components/Tabs/README.md b/components/Tabs/README.md index 64cd880..d4e764d 100644 --- a/components/Tabs/README.md +++ b/components/Tabs/README.md
@@ -63,21 +63,15 @@ `MDCTabBarView` is accessible by default. VoiceOver reads the titles of the `UITabBarItem`s contained within a tab bar as `accessibilityLabels`, and the `MDCTabBarView` handles setting the `accessibilityTraits` when tab bar items become selected and unselected. -## Types +**Types** -Material tabs can be broken into two main categories: fixed and scrollable. +Material tabs can be broken into two main categories: 1\. Fixed tabs 2\. Scrollable tabs -## Fixed tabs - - - -## Scrollable tabs - - + ### Tabs example -`MDCTabBarView` supports both fixed and scrolling tabs. By default, `MDCTabbarView` has a fixed layout. To set it up for scrolling, set the `preferredLayoutStyle` property to `.scrolling`. To receive updates about user actions, set the `delegate` property to an object conforming to `MDCTabBarViewDelegate`. Here is a simple set up of an `MDCTabBarView`: +`MDCTabBarView` supports both fixed and scrolling tabs. By default, `MDCTabbarView` has a fixed layout. To set it up for scrolling, set the `preferredLayoutStyle` property to `.scrollable`. To receive updates about user actions, set the `delegate` property to an object conforming to `MDCTabBarViewDelegate`. Here is a simple set up of an `MDCTabBarView`: <!--<div class="material-code-render" markdown="1">--> #### Swift @@ -88,6 +82,7 @@ UITabBarItem(title: "Recents", image: UIImage(named: "phone"), tag: 0), UITabBarItem(title: "Favorites", image: UIImage(named: "heart"), tag: 0), ] +tabBarView.preferredLayoutStyle = .scrollable // or .fixed view.addSubview(tabBarView) // Configure constraints ``` @@ -100,6 +95,7 @@ [[UITabBarItem alloc] initWithTitle:@"Recents" image:[UIImage imageNamed:@"phone"] tag:0], [[UITabBarItem alloc] initWithTitle:@"Favorites" image:[UIImage imageNamed:@"heart"] tag:0], ]; +tabBarView.preferredLayoutStyle = MDCTabBarViewLayoutStyleScrollable; // or MDCTabBarViewLayoutStyleFixed [self.view addSubview:tabBarView]; // Configure constraints ```
diff --git a/components/Tabs/docs/assets/tabs-fixed-hero.png b/components/Tabs/docs/assets/tabs-fixed-hero.png deleted file mode 100644 index 079b9e0..0000000 --- a/components/Tabs/docs/assets/tabs-fixed-hero.png +++ /dev/null Binary files differ
diff --git a/components/Tabs/docs/assets/tabs-scrollable-hero.png b/components/Tabs/docs/assets/tabs-scrollable-hero.png deleted file mode 100644 index b7642ba..0000000 --- a/components/Tabs/docs/assets/tabs-scrollable-hero.png +++ /dev/null Binary files differ
diff --git a/components/Tabs/docs/assets/tabs-types.png b/components/Tabs/docs/assets/tabs-types.png new file mode 100644 index 0000000..68f3457 --- /dev/null +++ b/components/Tabs/docs/assets/tabs-types.png Binary files differ
diff --git a/components/Tabs/src/TabBarView/MDCTabBarView.h b/components/Tabs/src/TabBarView/MDCTabBarView.h index 91530e1..e0bf7c5 100644 --- a/components/Tabs/src/TabBarView/MDCTabBarView.h +++ b/components/Tabs/src/TabBarView/MDCTabBarView.h
@@ -255,7 +255,7 @@ @end -#if MDC_AVAILABLE_SDK_IOS(13_0) +#if MDC_AVAILABLE_SDK_IOS(13_0) && !TARGET_OS_TV /** This component supports UIKit's Large Content Viewer. It is recommended that images associated with each tab bar item be backed with a PDF image with "preserve vector data" enabled within the assets
diff --git a/components/Tabs/tests/snapshot/MDCTabBarSnapshotTests.m b/components/Tabs/tests/snapshot/MDCTabBarSnapshotTests.m index e23f9b7..42e9ca4 100644 --- a/components/Tabs/tests/snapshot/MDCTabBarSnapshotTests.m +++ b/components/Tabs/tests/snapshot/MDCTabBarSnapshotTests.m
@@ -414,18 +414,16 @@ - (void)testTabBarItemBadgeColors { // When self.tabBar.itemAppearance = MDCTabBarItemAppearanceTitledImages; - if (@available(iOS 10.0, *)) { - self.item1.badgeValue = kItemTitleShort3Latin; - self.item1.badgeColor = UIColor.cyanColor; - self.item2.badgeValue = kItemTitleShort1Latin; - self.item2.badgeColor = UIColor.orangeColor; - self.item3.badgeValue = kItemTitleShort2Latin; - self.item3.badgeColor = UIColor.blackColor; - self.item4.badgeValue = kItemTitleShort1Latin; - self.item4.badgeColor = UIColor.blueColor; - self.item5.badgeValue = kItemTitleShort3Latin; - self.item5.badgeColor = UIColor.whiteColor; - } + self.item1.badgeValue = kItemTitleShort3Latin; + self.item1.badgeColor = UIColor.cyanColor; + self.item2.badgeValue = kItemTitleShort1Latin; + self.item2.badgeColor = UIColor.orangeColor; + self.item3.badgeValue = kItemTitleShort2Latin; + self.item3.badgeColor = UIColor.blackColor; + self.item4.badgeValue = kItemTitleShort1Latin; + self.item4.badgeColor = UIColor.blueColor; + self.item5.badgeValue = kItemTitleShort3Latin; + self.item5.badgeColor = UIColor.whiteColor; self.tabBar.frame = CGRectMake(0, 0, 480, 100); [self.tabBar sizeToFit];
diff --git a/components/Tabs/tests/unit/TabBarView/MDCTabBarItemTests.m b/components/Tabs/tests/unit/MDCTabBarItemTests.m similarity index 100% rename from components/Tabs/tests/unit/TabBarView/MDCTabBarItemTests.m rename to components/Tabs/tests/unit/MDCTabBarItemTests.m
diff --git a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewIndicatorViewTests.m b/components/Tabs/tests/unit/MDCTabBarViewIndicatorViewTests.m similarity index 97% rename from components/Tabs/tests/unit/TabBarView/MDCTabBarViewIndicatorViewTests.m rename to components/Tabs/tests/unit/MDCTabBarViewIndicatorViewTests.m index f2a6d21..8f16b06 100644 --- a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewIndicatorViewTests.m +++ b/components/Tabs/tests/unit/MDCTabBarViewIndicatorViewTests.m
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "../../../src/TabBarView/private/MDCTabBarViewIndicatorView.h" +#import "../../src/TabBarView/private/MDCTabBarViewIndicatorView.h" #import <QuartzCore/QuartzCore.h> #import <XCTest/XCTest.h>
diff --git a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewItemViewTests.m b/components/Tabs/tests/unit/MDCTabBarViewItemViewTests.m similarity index 97% rename from components/Tabs/tests/unit/TabBarView/MDCTabBarViewItemViewTests.m rename to components/Tabs/tests/unit/MDCTabBarViewItemViewTests.m index 7c68153..4557331 100644 --- a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewItemViewTests.m +++ b/components/Tabs/tests/unit/MDCTabBarViewItemViewTests.m
@@ -15,9 +15,9 @@ #import <XCTest/XCTest.h> #import <CoreGraphics/CoreGraphics.h> -#import "../../../src/TabBarView/MDCTabBarView.h" -#import "../../../src/TabBarView/private/MDCTabBarViewItemView.h" -#import "../../../src/TabBarView/private/MDCTabBarViewItemViewDelegate.h" +#import "../../src/TabBarView/MDCTabBarView.h" +#import "../../src/TabBarView/private/MDCTabBarViewItemView.h" +#import "../../src/TabBarView/private/MDCTabBarViewItemViewDelegate.h" // Minimum width of an item view. static const CGFloat kMinWidth = 90;
diff --git a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewTests.m b/components/Tabs/tests/unit/MDCTabBarViewTests.m similarity index 99% rename from components/Tabs/tests/unit/TabBarView/MDCTabBarViewTests.m rename to components/Tabs/tests/unit/MDCTabBarViewTests.m index a5570f7..39258e4 100644 --- a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewTests.m +++ b/components/Tabs/tests/unit/MDCTabBarViewTests.m
@@ -14,7 +14,7 @@ #import <XCTest/XCTest.h> -#import "../../../src/TabBarView/private/MDCTabBarViewItemView.h" +#import "../../src/TabBarView/private/MDCTabBarViewItemView.h" #import "MaterialAvailability.h" #import "MaterialRipple.h" #import "MDCTabBarItem.h" @@ -1213,11 +1213,9 @@ // When self.tabBarView.accessibilityTraits = UIAccessibilityTraitLink; - if (@available(iOS 10.0, *)) { - // Then - XCTAssertEqual(self.tabBarView.accessibilityTraits, - UIAccessibilityTraitTabBar | UIAccessibilityTraitLink); - } + // Then + XCTAssertEqual(self.tabBarView.accessibilityTraits, + UIAccessibilityTraitTabBar | UIAccessibilityTraitLink); } #pragma mark - Custom APIs
diff --git a/components/Tabs/tests/unit/TabBarView/MDCTabBarViewThemingTests.m b/components/Tabs/tests/unit/MDCTabBarViewThemingTests.m similarity index 100% rename from components/Tabs/tests/unit/TabBarView/MDCTabBarViewThemingTests.m rename to components/Tabs/tests/unit/MDCTabBarViewThemingTests.m
diff --git a/components/Tabs/tests/unit/Theming/TabsThemingTests.m b/components/Tabs/tests/unit/TabsThemingTests.m similarity index 100% rename from components/Tabs/tests/unit/Theming/TabsThemingTests.m rename to components/Tabs/tests/unit/TabsThemingTests.m
diff --git a/components/TextControls/README.md b/components/TextControls/README.md index 6e7d3aa..35227e5 100644 --- a/components/TextControls/README.md +++ b/components/TextControls/README.md
@@ -66,16 +66,13 @@ <!--</div>--> -## Making text fields accessible +### Making text fields accessible Material iOS text field offerings either inherit from `UITextField` or they contain `UITextView` instances. Both of these classes are accessible by default, and generally work out of the box with VoiceOver. However, the text fields we provide make use of floating labels above the text and assistive labels below the text, which makes the VoiceOver behavior of our text fields slightly different. If `accessibilityLabel` is _not_ explictly set on a single-line text field or multi-line text area, the `accessibilityLabel` that VoiceOver reads is a concatenation of the floating label text, the entered text, and the assistive label text. If `accessibilityLabel` _is_ set, the screen reader will read whatever it is set to. If you would like fine-grained control over what VoiceOver reads for these classes it is probably best to set the `accessibilityLabel` yourself. -## Types +**Types** -Text fields come in two styles: - -1. [Filled text fields](#filled-text-field) -2. [Outlined text fields](#outlined-text-field) +There are two types of text fields: 1\. [filled text fields](#filled-text-field) 2\. [outlined text fields](#outlined-text-field) !["Text field examples of both filled and outlined types, each type showing both inactive and focused states. The filled text fields show a gray background
diff --git a/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.m b/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.m index d774159..291b569 100644 --- a/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.m +++ b/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.m
@@ -489,6 +489,7 @@ floatingLabelFrame:self.layout.labelFrameFloating normalFont:self.normalFont floatingFont:self.floatingFont + labelTruncationIsPresent:self.layout.labelTruncationIsPresent animationDuration:self.animationDuration completion:^(BOOL finished) { if (finished) {
diff --git a/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.h b/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.h index 3a380f9..3592008 100644 --- a/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.h +++ b/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.h
@@ -43,6 +43,8 @@ @property(nonatomic, strong, nonnull, readonly) NSArray<NSNumber *> *verticalGradientLocations; @property(nonatomic, strong, nonnull, readonly) NSArray<NSNumber *> *horizontalGradientLocations; +@property(nonatomic, assign) BOOL labelTruncationIsPresent; + /** Initializing an MDCBaseTextAreaLayout object with this initializer is tantamount to calculating a layout for a text area. The long parameter list includes everything that might impact
diff --git a/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.m b/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.m index a434d41..70f67be 100644 --- a/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.m +++ b/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.m
@@ -16,11 +16,10 @@ #import "MDCTextControlAssistiveLabelViewLayout.h" #import "MDCTextControlHorizontalPositioning.h" -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" #import "MDCTextControlSideViewSupport.h" #import "MDCTextControlVerticalPositioningReference.h" -#import <MDFInternationalization/MDFInternationalization.h> static const CGFloat kGradientBlurLength = (CGFloat)4.0; @@ -155,9 +154,23 @@ CGFloat textRectMaxX = displaysRightView ? rightViewMinX - horizontalInterItemPadding : textAreaWidth - rightEdgePadding; + CGFloat textRectWidth = textRectMaxX - textRectMinX; + CGSize labelSizeNormal = MDCTextControlLabelSizeWith(label.text, textRectWidth, font); + CGSize labelSizeFloating = MDCTextControlLabelSizeWith(label.text, textRectWidth, floatingFont); + BOOL normalLabelWillTruncate = labelSizeNormal.height > font.lineHeight; + BOOL floatingLabelWillTruncate = labelSizeFloating.height > floatingFont.lineHeight; + if (normalLabelWillTruncate) { + labelSizeNormal.height = font.lineHeight; + labelSizeNormal.width = textRectWidth; + } + if (floatingLabelWillTruncate) { + labelSizeFloating.height = floatingFont.lineHeight; + labelSizeFloating.width = textRectWidth; + } + self.labelTruncationIsPresent = normalLabelWillTruncate || floatingLabelWillTruncate; + CGRect floatingLabelFrame = - [self floatingLabelFrameWithText:label.text - floatingFont:floatingFont + [self floatingLabelFrameWithFloatingLabelSize:labelSizeFloating textRectMinX:textRectMinX textRectMaxX:textRectMaxX paddingBetweenContainerTopAndFloatingLabel:verticalPositioningReference @@ -166,8 +179,7 @@ CGFloat floatingLabelMaxY = CGRectGetMaxY(floatingLabelFrame); CGRect normalLabelFrame = - [self normalLabelFrameWithLabelText:label.text - font:font + [self normalLabelFrameWithNormalLabelSize:labelSizeNormal textRectMinX:textRectMinX textRectMaxX:textRectMaxX paddingBetweenContainerTopAndNormalLabel:verticalPositioningReference @@ -197,9 +209,8 @@ containerHeight = verticalPositioningReference.containerHeightWithoutFloatingLabel; normalLabelFrame.origin.y = textViewMinY; } - CGFloat textViewWidth = textRectMaxX - textRectMinX; CGFloat textViewHeight = containerHeight - bottomPadding - textViewMinY; - CGRect textViewFrame = CGRectMake(textRectMinX, textViewMinY, textViewWidth, textViewHeight); + CGRect textViewFrame = CGRectMake(textRectMinX, textViewMinY, textRectWidth, textViewHeight); self.placeholderLabelHidden = placeholderLabel.attributedText == nil; if (self.placeholderLabelHidden) { @@ -208,7 +219,7 @@ CGSize sizeThatFits = [placeholderLabel sizeThatFits:textViewFrame.size]; CGFloat placeholderLabelMinX = 0; if (isRTL) { - placeholderLabelMinX = textViewWidth - sizeThatFits.width; + placeholderLabelMinX = textRectWidth - sizeThatFits.width; } self.placeholderLabelFrame = CGRectMake(placeholderLabelMinX, 0, sizeThatFits.width, sizeThatFits.height); @@ -304,14 +315,11 @@ return CGRectMake(minX, minY, CGRectGetWidth(sideView.bounds), sideViewHeight); } -- (CGRect)normalLabelFrameWithLabelText:(NSString *)labelText - font:(UIFont *)font - textRectMinX:(CGFloat)textRectMinX - textRectMaxX:(CGFloat)textRectMaxX - paddingBetweenContainerTopAndNormalLabel:(CGFloat)paddingBetweenContainerTopAndNormalLabel - isRTL:(BOOL)isRTL { - CGFloat maxTextWidth = textRectMaxX - textRectMinX; - CGSize normalLabelSize = [self textSizeWithText:labelText font:font maxWidth:maxTextWidth]; +- (CGRect)normalLabelFrameWithNormalLabelSize:(CGSize)normalLabelSize + textRectMinX:(CGFloat)textRectMinX + textRectMaxX:(CGFloat)textRectMaxX + paddingBetweenContainerTopAndNormalLabel:(CGFloat)paddingBetweenContainerTopAndNormalLabel + isRTL:(BOOL)isRTL { CGFloat normalLabelMinX = textRectMinX; if (isRTL) { normalLabelMinX = textRectMaxX - normalLabelSize.width; @@ -321,14 +329,12 @@ normalLabelSize.height); } -- (CGRect)floatingLabelFrameWithText:(NSString *)text - floatingFont:(UIFont *)floatingFont - textRectMinX:(CGFloat)textRectMinX - textRectMaxX:(CGFloat)textRectMaxX - paddingBetweenContainerTopAndFloatingLabel:(CGFloat)paddingBetweenContainerTopAndFloatingLabel - isRTL:(BOOL)isRTL { - CGFloat maxTextWidth = textRectMaxX - textRectMinX; - CGSize floatingLabelSize = [self textSizeWithText:text font:floatingFont maxWidth:maxTextWidth]; +- (CGRect)floatingLabelFrameWithFloatingLabelSize:(CGSize)floatingLabelSize + textRectMinX:(CGFloat)textRectMinX + textRectMaxX:(CGFloat)textRectMaxX + paddingBetweenContainerTopAndFloatingLabel: + (CGFloat)paddingBetweenContainerTopAndFloatingLabel + isRTL:(BOOL)isRTL { CGFloat textMinY = paddingBetweenContainerTopAndFloatingLabel; CGFloat textMinX = textRectMinX; if (isRTL) {
diff --git a/components/TextControls/src/BaseTextFields/MDCBaseTextField.m b/components/TextControls/src/BaseTextFields/MDCBaseTextField.m index 1a227c5..127bb4e 100644 --- a/components/TextControls/src/BaseTextFields/MDCBaseTextField.m +++ b/components/TextControls/src/BaseTextFields/MDCBaseTextField.m
@@ -542,13 +542,9 @@ #pragma mark Dynamic Type - (void)setAdjustsFontForContentSizeCategory:(BOOL)adjustsFontForContentSizeCategory { - if (@available(iOS 10.0, *)) { - [super setAdjustsFontForContentSizeCategory:adjustsFontForContentSizeCategory]; - self.leadingAssistiveLabel.adjustsFontForContentSizeCategory = - adjustsFontForContentSizeCategory; - self.trailingAssistiveLabel.adjustsFontForContentSizeCategory = - adjustsFontForContentSizeCategory; - } + [super setAdjustsFontForContentSizeCategory:adjustsFontForContentSizeCategory]; + self.leadingAssistiveLabel.adjustsFontForContentSizeCategory = adjustsFontForContentSizeCategory; + self.trailingAssistiveLabel.adjustsFontForContentSizeCategory = adjustsFontForContentSizeCategory; } - (void)observeContentSizeCategoryNotifications { @@ -585,6 +581,7 @@ floatingLabelFrame:self.layout.labelFrameFloating normalFont:self.normalFont floatingFont:self.floatingFont + labelTruncationIsPresent:self.layout.labelTruncationIsPresent animationDuration:self.animationDuration completion:^(BOOL finished) { if (finished) {
diff --git a/components/TextControls/tests/snapshot/MDCBaseTextAreaSnapshotTests.m b/components/TextControls/tests/snapshot/MDCBaseTextAreaSnapshotTests.m index de75961..d0ec75b 100644 --- a/components/TextControls/tests/snapshot/MDCBaseTextAreaSnapshotTests.m +++ b/components/TextControls/tests/snapshot/MDCBaseTextAreaSnapshotTests.m
@@ -213,6 +213,17 @@ [self validateTextArea:textArea]; } +- (void)testTextAreaWithTruncatingNormalLabel { + // Given + MDCBaseTextArea *textArea = self.textArea; + + // When + textArea.label.text = @"Very long label text withaverylongwordinit"; + + // Then + [self validateTextArea:textArea]; +} + #pragma mark Helpers - (UIView *)createSideView {
diff --git a/components/TextControls/tests/snapshot/MDCBaseTextFieldSnapshotTests.m b/components/TextControls/tests/snapshot/MDCBaseTextFieldSnapshotTests.m index e35bfa5..ae25b47 100644 --- a/components/TextControls/tests/snapshot/MDCBaseTextFieldSnapshotTests.m +++ b/components/TextControls/tests/snapshot/MDCBaseTextFieldSnapshotTests.m
@@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#import "MaterialTextControls+BaseTextFields.h" #import "MaterialSnapshot.h" #import <UIKit/UIKit.h> @@ -280,4 +281,15 @@ [self validateTextField:textField]; } +- (void)testTextFieldWithTruncatingNormalLabel { + // Given + MDCBaseTextField *textField = self.textField; + + // When + textField.label.text = @"Very long label text withaverylongwordinit"; + + // Then + [self validateTextField:textField]; +} + @end
diff --git a/components/TextControls/tests/snapshot/supplemental/MDCTextControlSnapshotTestHelpers.m b/components/TextControls/tests/snapshot/supplemental/MDCTextControlSnapshotTestHelpers.m index 79f72e8..a8b634d 100644 --- a/components/TextControls/tests/snapshot/supplemental/MDCTextControlSnapshotTestHelpers.m +++ b/components/TextControls/tests/snapshot/supplemental/MDCTextControlSnapshotTestHelpers.m
@@ -60,11 +60,9 @@ } + (void)applyContentSizeCategory:(UIContentSizeCategory)contentSizeCategory { - if (@available(iOS 10.0, *)) { - UITraitCollection *traitCollection = - [UITraitCollection traitCollectionWithPreferredContentSizeCategory:contentSizeCategory]; - [MDCTextControlSnapshotTestHelpers updateTraitCollectionWithTraitCollection:traitCollection]; - } + UITraitCollection *traitCollection = + [UITraitCollection traitCollectionWithPreferredContentSizeCategory:contentSizeCategory]; + [MDCTextControlSnapshotTestHelpers updateTraitCollectionWithTraitCollection:traitCollection]; } + (void)updateTraitCollectionWithTraitCollection:(UITraitCollection *)traitCollection {
diff --git a/components/TextControls/tests/unit/BaseTextAreas/MDCBaseTextAreaTests.m b/components/TextControls/tests/unit/MDCBaseTextAreaTests.m similarity index 93% rename from components/TextControls/tests/unit/BaseTextAreas/MDCBaseTextAreaTests.m rename to components/TextControls/tests/unit/MDCBaseTextAreaTests.m index d138ff8..10197c1 100644 --- a/components/TextControls/tests/unit/BaseTextAreas/MDCBaseTextAreaTests.m +++ b/components/TextControls/tests/unit/MDCBaseTextAreaTests.m
@@ -15,7 +15,7 @@ #import <XCTest/XCTest.h> #import "MaterialTextControls+BaseTextAreas.h" -#import "MaterialTextControlsPrivate+BaseStyle.h" +#import "MDCTextControlState.h" @interface MDCBaseTextArea (Private) - (BOOL)shouldLayoutForRTL; @@ -131,19 +131,17 @@ } - (void)testAdjustsFontForContentSizeCategory { - if (@available(iOS 10.0, *)) { - // Given - CGRect textAreaFrame = CGRectMake(0, 0, 130, 100); - MDCBaseTextArea *textArea = [[MDCBaseTextArea alloc] initWithFrame:textAreaFrame]; + // Given + CGRect textAreaFrame = CGRectMake(0, 0, 130, 100); + MDCBaseTextArea *textArea = [[MDCBaseTextArea alloc] initWithFrame:textAreaFrame]; - // When - textArea.adjustsFontForContentSizeCategory = YES; + // When + textArea.adjustsFontForContentSizeCategory = YES; - // Then - XCTAssertTrue(textArea.adjustsFontForContentSizeCategory); - XCTAssertTrue(textArea.leadingAssistiveLabel.adjustsFontForContentSizeCategory); - XCTAssertTrue(textArea.trailingAssistiveLabel.adjustsFontForContentSizeCategory); - } + // Then + XCTAssertTrue(textArea.adjustsFontForContentSizeCategory); + XCTAssertTrue(textArea.leadingAssistiveLabel.adjustsFontForContentSizeCategory); + XCTAssertTrue(textArea.trailingAssistiveLabel.adjustsFontForContentSizeCategory); } - (void)testIntrinsicContentInvalidationWhenWidthChanges {
diff --git a/components/TextControls/tests/unit/BaseTextFields/MDCBaseTextFieldTests.m b/components/TextControls/tests/unit/MDCBaseTextFieldTests.m similarity index 96% rename from components/TextControls/tests/unit/BaseTextFields/MDCBaseTextFieldTests.m rename to components/TextControls/tests/unit/MDCBaseTextFieldTests.m index c9acfdf..0bd7226 100644 --- a/components/TextControls/tests/unit/BaseTextFields/MDCBaseTextFieldTests.m +++ b/components/TextControls/tests/unit/MDCBaseTextFieldTests.m
@@ -15,6 +15,7 @@ #import <XCTest/XCTest.h> #import "MaterialTextControls+BaseTextFields.h" +#import "MaterialTextControls+Enums.h" #import "MaterialTextControlsPrivate+BaseStyle.h" @interface MDCBaseTextField (Private) @@ -352,19 +353,17 @@ } - (void)testAdjustsFontForContentSizeCategory { - if (@available(iOS 10.0, *)) { - // Given - CGRect textFieldFrame = CGRectMake(0, 0, 130, 100); - MDCBaseTextField *textField = [[MDCBaseTextField alloc] initWithFrame:textFieldFrame]; + // Given + CGRect textFieldFrame = CGRectMake(0, 0, 130, 100); + MDCBaseTextField *textField = [[MDCBaseTextField alloc] initWithFrame:textFieldFrame]; - // When - textField.adjustsFontForContentSizeCategory = YES; + // When + textField.adjustsFontForContentSizeCategory = YES; - // Then - XCTAssertTrue(textField.adjustsFontForContentSizeCategory); - XCTAssertTrue(textField.leadingAssistiveLabel.adjustsFontForContentSizeCategory); - XCTAssertTrue(textField.trailingAssistiveLabel.adjustsFontForContentSizeCategory); - } + // Then + XCTAssertTrue(textField.adjustsFontForContentSizeCategory); + XCTAssertTrue(textField.leadingAssistiveLabel.adjustsFontForContentSizeCategory); + XCTAssertTrue(textField.trailingAssistiveLabel.adjustsFontForContentSizeCategory); } - (void)testIntrinsicContentInvalidationWhenWidthChanges {
diff --git a/components/TextControls/tests/unit/FilledTextAreas/MDCFilledTextAreaTests.m b/components/TextControls/tests/unit/MDCFilledTextAreaTests.m similarity index 98% rename from components/TextControls/tests/unit/FilledTextAreas/MDCFilledTextAreaTests.m rename to components/TextControls/tests/unit/MDCFilledTextAreaTests.m index 217a8cd..6ab4312 100644 --- a/components/TextControls/tests/unit/FilledTextAreas/MDCFilledTextAreaTests.m +++ b/components/TextControls/tests/unit/MDCFilledTextAreaTests.m
@@ -14,6 +14,7 @@ #import <XCTest/XCTest.h> +#import "MDCTextControlState.h" #import "MaterialTextControls+FilledTextAreas.h" @interface MDCFilledTextAreaTests : XCTestCase
diff --git a/components/TextControls/tests/unit/FilledTextAreasTheming/MDCFilledTextAreaThemingTests.m b/components/TextControls/tests/unit/MDCFilledTextAreaThemingTests.m similarity index 98% rename from components/TextControls/tests/unit/FilledTextAreasTheming/MDCFilledTextAreaThemingTests.m rename to components/TextControls/tests/unit/MDCFilledTextAreaThemingTests.m index 07afa75..dd2a6ae 100644 --- a/components/TextControls/tests/unit/FilledTextAreasTheming/MDCFilledTextAreaThemingTests.m +++ b/components/TextControls/tests/unit/MDCFilledTextAreaThemingTests.m
@@ -14,8 +14,12 @@ #import <XCTest/XCTest.h> +#import "MDCTextControlState.h" +#import "MDCFilledTextArea.h" +#import "MaterialColorScheme.h" #import "MaterialContainerScheme.h" #import "MaterialTextControls+FilledTextAreasTheming.h" +#import "MaterialTypographyScheme.h" static const CGFloat kDisabledOpacity = (CGFloat)0.60;
diff --git a/components/TextControls/tests/unit/FilledTextFields/MDCFilledTextFieldTests.m b/components/TextControls/tests/unit/MDCFilledTextFieldTests.m similarity index 98% rename from components/TextControls/tests/unit/FilledTextFields/MDCFilledTextFieldTests.m rename to components/TextControls/tests/unit/MDCFilledTextFieldTests.m index 3957512..6ff8b0f 100644 --- a/components/TextControls/tests/unit/FilledTextFields/MDCFilledTextFieldTests.m +++ b/components/TextControls/tests/unit/MDCFilledTextFieldTests.m
@@ -14,6 +14,7 @@ #import <XCTest/XCTest.h> +#import "MaterialTextControls+Enums.h" #import "MaterialTextControls+FilledTextFields.h" @interface MDCFilledTextFieldTests : XCTestCase
diff --git a/components/TextControls/tests/unit/FilledTextFieldsTheming/MDCFilledTextFieldThemingTests.m b/components/TextControls/tests/unit/MDCFilledTextFieldThemingTests.m similarity index 98% rename from components/TextControls/tests/unit/FilledTextFieldsTheming/MDCFilledTextFieldThemingTests.m rename to components/TextControls/tests/unit/MDCFilledTextFieldThemingTests.m index 5382f88..dc66600 100644 --- a/components/TextControls/tests/unit/FilledTextFieldsTheming/MDCFilledTextFieldThemingTests.m +++ b/components/TextControls/tests/unit/MDCFilledTextFieldThemingTests.m
@@ -14,8 +14,12 @@ #import <XCTest/XCTest.h> +#import "MaterialTextControls+Enums.h" +#import "MaterialTextControls+FilledTextFields.h" +#import "MaterialColorScheme.h" #import "MaterialContainerScheme.h" #import "MaterialTextControls+FilledTextFieldsTheming.h" +#import "MaterialTypographyScheme.h" static const CGFloat kDisabledOpacity = (CGFloat)0.60;
diff --git a/components/TextControls/tests/unit/OutlinedTextAreas/MDCOutlinedTextAreaTests.m b/components/TextControls/tests/unit/MDCOutlinedTextAreaTests.m similarity index 98% rename from components/TextControls/tests/unit/OutlinedTextAreas/MDCOutlinedTextAreaTests.m rename to components/TextControls/tests/unit/MDCOutlinedTextAreaTests.m index 94fed9d..f076b8d 100644 --- a/components/TextControls/tests/unit/OutlinedTextAreas/MDCOutlinedTextAreaTests.m +++ b/components/TextControls/tests/unit/MDCOutlinedTextAreaTests.m
@@ -15,6 +15,7 @@ #import <XCTest/XCTest.h> #import "MaterialAvailability.h" +#import "MDCTextControlState.h" #import "MaterialTextControls+OutlinedTextAreas.h" @interface MDCOutlinedTextAreaTests : XCTestCase
diff --git a/components/TextControls/tests/unit/OutlinedTextAreasTheming/MDCOutlinedTextAreaThemingTests.m b/components/TextControls/tests/unit/MDCOutlinedTextAreaThemingTests.m similarity index 98% rename from components/TextControls/tests/unit/OutlinedTextAreasTheming/MDCOutlinedTextAreaThemingTests.m rename to components/TextControls/tests/unit/MDCOutlinedTextAreaThemingTests.m index 85dfb10..595eaf1 100644 --- a/components/TextControls/tests/unit/OutlinedTextAreasTheming/MDCOutlinedTextAreaThemingTests.m +++ b/components/TextControls/tests/unit/MDCOutlinedTextAreaThemingTests.m
@@ -14,8 +14,12 @@ #import <XCTest/XCTest.h> +#import "MDCTextControlState.h" +#import "MDCOutlinedTextArea.h" +#import "MaterialColorScheme.h" #import "MaterialContainerScheme.h" #import "MaterialTextControls+OutlinedTextAreasTheming.h" +#import "MaterialTypographyScheme.h" static const CGFloat kDisabledOpacity = (CGFloat)0.60;
diff --git a/components/TextControls/tests/unit/OutlinedTextFields/MDCOutlinedTextFieldTests.m b/components/TextControls/tests/unit/MDCOutlinedTextFieldTests.m similarity index 98% rename from components/TextControls/tests/unit/OutlinedTextFields/MDCOutlinedTextFieldTests.m rename to components/TextControls/tests/unit/MDCOutlinedTextFieldTests.m index 6e99a1f..7fdcfb1 100644 --- a/components/TextControls/tests/unit/OutlinedTextFields/MDCOutlinedTextFieldTests.m +++ b/components/TextControls/tests/unit/MDCOutlinedTextFieldTests.m
@@ -15,6 +15,7 @@ #import <XCTest/XCTest.h> #import "MaterialAvailability.h" +#import "MaterialTextControls+Enums.h" #import "MaterialTextControls+OutlinedTextFields.h" @interface MDCOutlinedTextFieldTests : XCTestCase
diff --git a/components/TextControls/tests/unit/OutlinedTextFieldsTheming/MDCOutlinedTextFieldThemingTests.m b/components/TextControls/tests/unit/MDCOutlinedTextFieldThemingTests.m similarity index 98% rename from components/TextControls/tests/unit/OutlinedTextFieldsTheming/MDCOutlinedTextFieldThemingTests.m rename to components/TextControls/tests/unit/MDCOutlinedTextFieldThemingTests.m index f923a2e..600f3ef 100644 --- a/components/TextControls/tests/unit/OutlinedTextFieldsTheming/MDCOutlinedTextFieldThemingTests.m +++ b/components/TextControls/tests/unit/MDCOutlinedTextFieldThemingTests.m
@@ -14,8 +14,12 @@ #import <XCTest/XCTest.h> +#import "MaterialTextControls+Enums.h" +#import "MaterialTextControls+OutlinedTextFields.h" +#import "MaterialColorScheme.h" #import "MaterialContainerScheme.h" #import "MaterialTextControls+OutlinedTextFieldsTheming.h" +#import "MaterialTypographyScheme.h" static const CGFloat kDisabledOpacity = (CGFloat)0.60;
diff --git a/components/TextControls/tests/unit/UnderlinedTextFields/MDCUnderlinedTextFieldTests.m b/components/TextControls/tests/unit/MDCUnderlinedTextFieldTests.m similarity index 100% rename from components/TextControls/tests/unit/UnderlinedTextFields/MDCUnderlinedTextFieldTests.m rename to components/TextControls/tests/unit/MDCUnderlinedTextFieldTests.m
diff --git a/components/TextControls/tests/unit/UnderlinedTextFieldsTheming/MDCUnderlinedTextFieldThemingTests.m b/components/TextControls/tests/unit/MDCUnderlinedTextFieldThemingTests.m similarity index 100% rename from components/TextControls/tests/unit/UnderlinedTextFieldsTheming/MDCUnderlinedTextFieldThemingTests.m rename to components/TextControls/tests/unit/MDCUnderlinedTextFieldThemingTests.m
diff --git a/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCMultilineTextField.m b/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCMultilineTextField.m index d0f7989..bdfdf43 100644 --- a/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCMultilineTextField.m +++ b/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCMultilineTextField.m
@@ -54,10 +54,7 @@ if (_isEffectiveUserInterfaceLayoutDirectionOverridden) { return _effectiveUserInterfaceLayoutDirection; } - if (@available(iOS 10.0, *)) { - return [super effectiveUserInterfaceLayoutDirection]; - } - return UIApplication.sharedApplication.userInterfaceLayoutDirection; + return [super effectiveUserInterfaceLayoutDirection]; } - (void)MDCtest_setEffectiveUserInterfaceLayoutDirection:(UIUserInterfaceLayoutDirection)direction {
diff --git a/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCTextField.m b/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCTextField.m index 6e284a3..a91a61c 100644 --- a/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCTextField.m +++ b/components/TextFields/tests/snapshot/supplemental/SnapshotFakeMDCTextField.m
@@ -13,8 +13,8 @@ // limitations under the License. #import <UIKit/UIKit.h> -#import <MDFInternationalization/MDFInternationalization.h> #import "SnapshotFakeMDCTextField.h" +#import <MDFInternationalization/MDFInternationalization.h> @implementation SnapshotFakeMDCTextField { BOOL _isEditing; @@ -56,10 +56,7 @@ return _effectiveUserInterfaceLayoutDirection; } - if (@available(iOS 10.0, *)) { - return [super effectiveUserInterfaceLayoutDirection]; - } - return UIApplication.sharedApplication.userInterfaceLayoutDirection; + return [super effectiveUserInterfaceLayoutDirection]; } - (void)MDCtest_setEffectiveUserInterfaceLayoutDirection:(UIUserInterfaceLayoutDirection)direction {
diff --git a/components/TextFields/tests/unit/Theming/MDCTextFieldControllerUnderline_MaterialThemingTests.swift b/components/TextFields/tests/unit/MDCTextFieldControllerUnderline_MaterialThemingTests.swift similarity index 100% rename from components/TextFields/tests/unit/Theming/MDCTextFieldControllerUnderline_MaterialThemingTests.swift rename to components/TextFields/tests/unit/MDCTextFieldControllerUnderline_MaterialThemingTests.swift
diff --git a/components/TextFields/tests/unit/MDCTextInputCommonFundamentTests.m b/components/TextFields/tests/unit/MDCTextInputCommonFundamentTests.m index a3dc142..5ad65a5 100644 --- a/components/TextFields/tests/unit/MDCTextInputCommonFundamentTests.m +++ b/components/TextFields/tests/unit/MDCTextInputCommonFundamentTests.m
@@ -16,6 +16,7 @@ #import "../../src/private/MDCTextInputCommonFundament.h" #import "MaterialTextFields.h" +#import "UIFont+MaterialSimpleEquality.h" /** Unit tests for @c MDCTextInputCommonFundament. */ @interface MDCTextInputCommonFundamentTests : XCTestCase @@ -40,9 +41,21 @@ - (void)testDefaultFontValues { // Then - XCTAssertNotNil(self.textInput.font); + if (@available(iOS 14, *)) { + // TODO(b/184185897): Evaluate why this is different on iOS 14. + XCTAssertNil(self.textInput.font); + } else { + XCTAssertNotNil(self.textInput.font); + } XCTAssertNotNil(self.textInput.placeholderLabel); - XCTAssertEqual(self.textInput.font, self.textInput.placeholderLabel.font); + if (@available(iOS 14, *)) { + // TODO(b/184185897): Evaluate why this is different on iOS 14. + XCTAssertNil(self.textInput.font); + } else { + XCTAssertTrue([self.textInput.font mdc_isSimplyEqual:self.textInput.placeholderLabel.font], + @"%@ is not equal to %@", self.textInput.font, + self.textInput.placeholderLabel.font); + } } - (void)testDidSetFontChangesFontUpdatesPlaceholderFontWhenFontsMatch { @@ -57,8 +70,16 @@ [self.textInput didSetFont:originalFont]; // Then - XCTAssertEqual(self.textInput.font, assignedFont); - XCTAssertEqual(self.textInput.placeholderLabel.font, self.textInput.font); + if (@available(iOS 14, *)) { + // TODO(b/184185897): Evaluate why this is different on iOS 14. + XCTAssertNil(self.textInput.font); + } else { + XCTAssertTrue([self.textInput.font mdc_isSimplyEqual:assignedFont], @"%@ is not equal to %@", + self.textInput.font, assignedFont); + XCTAssertTrue([self.textInput.placeholderLabel.font mdc_isSimplyEqual:self.textInput.font], + @"%@ is not equal to %@", self.textInput.placeholderLabel.font, + self.textInput.font); + } } - (void)testDidSetFontChangesFontDoesNotUpdatePlaceholderFontWhenFontsDoNotMatch { @@ -73,7 +94,12 @@ [self.textInput didSetFont:originalFont]; // Then - XCTAssertEqual(self.textInput.font, assignedFont); + if (@available(iOS 14, *)) { + // TODO(b/184185897): Evaluate why this is different on iOS 14. + XCTAssertNil(self.textInput.font); + } else { + XCTAssertEqual(self.textInput.font, assignedFont); + } XCTAssertNotEqual(self.textInput.placeholderLabel.font, self.textInput.font); }
diff --git a/components/TextFields/tests/unit/TextFieldControllerClassPropertiesTests.swift b/components/TextFields/tests/unit/TextFieldControllerClassPropertiesTests.swift index 7d86f85..2415ef0 100644 --- a/components/TextFields/tests/unit/TextFieldControllerClassPropertiesTests.swift +++ b/components/TextFields/tests/unit/TextFieldControllerClassPropertiesTests.swift
@@ -43,7 +43,7 @@ MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault = nil MDCTextInputControllerFilled.floatingPlaceholderScaleDefault = 0.75 - MDCTextInputControllerFilled.textInputClearButtonTintColorDefault = nil; + MDCTextInputControllerFilled.textInputClearButtonTintColorDefault = nil MDCTextInputControllerOutlined.roundedCornersDefault = [] MDCTextInputControllerOutlined.errorColorDefault = nil @@ -65,7 +65,7 @@ MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault = nil MDCTextInputControllerOutlined.floatingPlaceholderScaleDefault = 0.75 MDCTextInputControllerOutlined.isFloatingEnabledDefault = true - MDCTextInputControllerOutlined.textInputClearButtonTintColorDefault = nil; + MDCTextInputControllerOutlined.textInputClearButtonTintColorDefault = nil MDCTextInputControllerUnderline.roundedCornersDefault = [] MDCTextInputControllerUnderline.errorColorDefault = nil @@ -87,7 +87,7 @@ MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault = nil MDCTextInputControllerUnderline.floatingPlaceholderScaleDefault = 0.75 MDCTextInputControllerUnderline.isFloatingEnabledDefault = true - MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault = nil; + MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault = nil MDCTextInputControllerFullWidth.errorColorDefault = nil MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault = nil @@ -103,7 +103,7 @@ MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault = nil MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault = nil MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault = nil - + MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault = nil } @@ -111,41 +111,52 @@ // Test the values of the class properties. XCTAssertEqual(MDCTextInputControllerFilled.errorColorDefault, MDCPalette.red.accent400) - XCTAssertEqual(MDCTextInputControllerFilled.inlinePlaceholderColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerFilled.inlinePlaceholderColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) XCTAssertEqual(MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault, false) - XCTAssertEqual(MDCTextInputControllerFilled.activeColorDefault, - MDCPalette.blue.accent700) + XCTAssertEqual( + MDCTextInputControllerFilled.activeColorDefault, + MDCPalette.blue.accent700) XCTAssertEqual(MDCTextInputControllerFilled.normalColorDefault, .lightGray) XCTAssertEqual(MDCTextInputControllerFilled.underlineHeightActiveDefault, 2) XCTAssertEqual(MDCTextInputControllerFilled.underlineHeightNormalDefault, 1) XCTAssertEqual(MDCTextInputControllerFilled.underlineViewModeDefault, .whileEditing) - XCTAssertEqual(MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault, - MDCTextInputControllerFilled.inlinePlaceholderColorDefault) - XCTAssertEqual(MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault, - MDCTextInputControllerFilled.inlinePlaceholderColorDefault) + XCTAssertEqual( + MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault, + MDCTextInputControllerFilled.inlinePlaceholderColorDefault) + XCTAssertEqual( + MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault, + MDCTextInputControllerFilled.inlinePlaceholderColorDefault) - XCTAssertEqual(MDCTextInputControllerFilled.inlinePlaceholderFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) - XCTAssertEqual(MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault, - MDCTextInputControllerFilled.trailingUnderlineLabelFontDefault) - XCTAssertEqual(MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) + XCTAssertEqual( + MDCTextInputControllerFilled.inlinePlaceholderFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) + XCTAssertEqual( + MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault, + MDCTextInputControllerFilled.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) // Default specific properties - XCTAssertEqual(MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault, - MDCTextInputControllerFilled.activeColorDefault) + XCTAssertEqual( + MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault, + MDCTextInputControllerFilled.activeColorDefault) - XCTAssertEqual(MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) XCTAssertEqual(Float(MDCTextInputControllerFilled.floatingPlaceholderScaleDefault), 0.75) XCTAssertEqual(MDCTextInputControllerFilled.isFloatingEnabledDefault, true) - XCTAssertEqual(MDCTextInputControllerFilled.roundedCornersDefault, - [UIRectCorner.topLeft, .topRight]) + // TODO(b/184185897): Evaluate why this is flaky. + XCTAssertEqual(MDCTextInputControllerFilled.roundedCornersDefault, []) XCTAssertNil(MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) @@ -154,40 +165,55 @@ var controller = MDCTextInputControllerFilled(textInput: textField) XCTAssertEqual(controller.errorColor, MDCTextInputControllerFilled.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerFilled.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerFilled.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerFilled.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerFilled.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerFilled.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerFilled.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerFilled.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerFilled.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerFilled.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerFilled.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerFilled.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerFilled.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerFilled.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerFilled.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerFilled.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerFilled.trailingUnderlineLabelFontDefault) // Default specific properties - XCTAssertEqual(controller.floatingPlaceholderActiveColor, - MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderActiveColor, + MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault) - XCTAssertEqual(controller.floatingPlaceholderNormalColor, - MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault) - XCTAssertEqual(controller.isFloatingEnabled, - MDCTextInputControllerFilled.isFloatingEnabledDefault) + XCTAssertEqual( + controller.floatingPlaceholderNormalColor, + MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault) + XCTAssertEqual( + controller.isFloatingEnabled, + MDCTextInputControllerFilled.isFloatingEnabledDefault) XCTAssertEqual(controller.roundedCorners, MDCTextInputControllerFilled.roundedCornersDefault) // Test the changes to the class properties. @@ -198,8 +224,9 @@ XCTAssertEqual(MDCTextInputControllerFilled.inlinePlaceholderColorDefault, .orange) MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault = false - XCTAssertEqual(MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault, - false) + XCTAssertEqual( + MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault, + false) MDCTextInputControllerFilled.activeColorDefault = .purple XCTAssertEqual(MDCTextInputControllerFilled.activeColorDefault, .purple) @@ -223,16 +250,19 @@ XCTAssertEqual(MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault, .cyan) MDCTextInputControllerFilled.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 4) - XCTAssertEqual(MDCTextInputControllerFilled.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 4)) + XCTAssertEqual( + MDCTextInputControllerFilled.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 4)) MDCTextInputControllerFilled.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 5) - XCTAssertEqual(MDCTextInputControllerFilled.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 5)) + XCTAssertEqual( + MDCTextInputControllerFilled.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 5)) MDCTextInputControllerFilled.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 6) - XCTAssertEqual(MDCTextInputControllerFilled.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 6)) + XCTAssertEqual( + MDCTextInputControllerFilled.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 6)) // Default specific properties MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault = .yellow @@ -254,38 +284,52 @@ controller = MDCTextInputControllerFilled(textInput: textField) XCTAssertEqual(controller.errorColor, MDCTextInputControllerFilled.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerFilled.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerFilled.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerFilled.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerFilled.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerFilled.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerFilled.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerFilled.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerFilled.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerFilled.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerFilled.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerFilled.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerFilled.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerFilled.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerFilled.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerFilled.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerFilled.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerFilled.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerFilled.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerFilled.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerFilled.trailingUnderlineLabelFontDefault) // Default specific properties - XCTAssertEqual(controller.floatingPlaceholderActiveColor, - MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderActiveColor, + MDCTextInputControllerFilled.floatingPlaceholderActiveColorDefault) - XCTAssertEqual(controller.floatingPlaceholderNormalColor, - MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderNormalColor, + MDCTextInputControllerFilled.floatingPlaceholderNormalColorDefault) XCTAssertEqual(controller.roundedCorners, MDCTextInputControllerFilled.roundedCornersDefault) } @@ -293,41 +337,53 @@ func testOutlined() { // Test the values of the class properties. XCTAssertEqual(MDCTextInputControllerOutlined.errorColorDefault, MDCPalette.red.accent400) - XCTAssertEqual(MDCTextInputControllerOutlined.inlinePlaceholderColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault, false) - XCTAssertEqual(MDCTextInputControllerOutlined.activeColorDefault, - MDCPalette.blue.accent700) + XCTAssertEqual( + MDCTextInputControllerOutlined.inlinePlaceholderColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault, false) + XCTAssertEqual( + MDCTextInputControllerOutlined.activeColorDefault, + MDCPalette.blue.accent700) XCTAssertEqual(MDCTextInputControllerOutlined.normalColorDefault, .lightGray) XCTAssertEqual(MDCTextInputControllerOutlined.underlineHeightActiveDefault, 0) XCTAssertEqual(MDCTextInputControllerOutlined.underlineHeightNormalDefault, 0) XCTAssertEqual(MDCTextInputControllerOutlined.underlineViewModeDefault, .whileEditing) - XCTAssertEqual(MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault, - MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) - XCTAssertEqual(MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault, - MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) + XCTAssertEqual( + MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault, + MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) + XCTAssertEqual( + MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault, + MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) - XCTAssertEqual(MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) - XCTAssertEqual(MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault, - MDCTextInputControllerOutlined.trailingUnderlineLabelFontDefault) - XCTAssertEqual(MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) + XCTAssertEqual( + MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) + XCTAssertEqual( + MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault, + MDCTextInputControllerOutlined.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) // Default specific properties - XCTAssertEqual(MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault, - MDCTextInputControllerOutlined.activeColorDefault) + XCTAssertEqual( + MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault, + MDCTextInputControllerOutlined.activeColorDefault) - XCTAssertEqual(MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) XCTAssertEqual(Float(MDCTextInputControllerOutlined.floatingPlaceholderScaleDefault), 0.75) XCTAssertEqual(MDCTextInputControllerOutlined.isFloatingEnabledDefault, true) XCTAssertEqual(MDCTextInputControllerOutlined.roundedCornersDefault, []) - + XCTAssertNil(MDCTextInputControllerOutlined.textInputClearButtonTintColorDefault) // Test the use of the class properties. @@ -335,40 +391,55 @@ var controller = MDCTextInputControllerOutlined(textInput: textField) XCTAssertEqual(controller.errorColor, MDCTextInputControllerOutlined.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerOutlined.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerOutlined.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerOutlined.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerOutlined.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerOutlined.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerOutlined.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerOutlined.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerOutlined.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerOutlined.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerOutlined.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerOutlined.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerOutlined.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerOutlined.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerOutlined.trailingUnderlineLabelFontDefault) // Default specific properties - XCTAssertEqual(controller.floatingPlaceholderActiveColor, - MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderActiveColor, + MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault) - XCTAssertEqual(controller.floatingPlaceholderNormalColor, - MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault) - XCTAssertEqual(controller.isFloatingEnabled, - MDCTextInputControllerOutlined.isFloatingEnabledDefault) + XCTAssertEqual( + controller.floatingPlaceholderNormalColor, + MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault) + XCTAssertEqual( + controller.isFloatingEnabled, + MDCTextInputControllerOutlined.isFloatingEnabledDefault) XCTAssertEqual(controller.roundedCorners, MDCTextInputControllerOutlined.roundedCornersDefault) // Test the changes to the class properties. @@ -379,8 +450,9 @@ XCTAssertEqual(MDCTextInputControllerOutlined.inlinePlaceholderColorDefault, .orange) MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault = false - XCTAssertEqual(MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault, - false) + XCTAssertEqual( + MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault, + false) MDCTextInputControllerOutlined.activeColorDefault = .purple XCTAssertEqual(MDCTextInputControllerOutlined.activeColorDefault, .purple) @@ -404,16 +476,19 @@ XCTAssertEqual(MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault, .gray) MDCTextInputControllerOutlined.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 4) - XCTAssertEqual(MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 4)) + XCTAssertEqual( + MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 4)) MDCTextInputControllerOutlined.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 5) - XCTAssertEqual(MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 5)) + XCTAssertEqual( + MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 5)) MDCTextInputControllerOutlined.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 6) - XCTAssertEqual(MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 6)) + XCTAssertEqual( + MDCTextInputControllerOutlined.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 6)) // Default specific properties MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault = .clear @@ -435,38 +510,52 @@ controller = MDCTextInputControllerOutlined(textInput: textField) XCTAssertEqual(controller.errorColor, MDCTextInputControllerOutlined.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerOutlined.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerOutlined.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerOutlined.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerOutlined.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerOutlined.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerOutlined.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerOutlined.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerOutlined.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerOutlined.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerOutlined.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerOutlined.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerOutlined.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerOutlined.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerOutlined.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerOutlined.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerOutlined.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerOutlined.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerOutlined.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerOutlined.trailingUnderlineLabelFontDefault) // Default specific properties - XCTAssertEqual(controller.floatingPlaceholderActiveColor, - MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderActiveColor, + MDCTextInputControllerOutlined.floatingPlaceholderActiveColorDefault) - XCTAssertEqual(controller.floatingPlaceholderNormalColor, - MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderNormalColor, + MDCTextInputControllerOutlined.floatingPlaceholderNormalColorDefault) XCTAssertEqual(controller.roundedCorners, MDCTextInputControllerOutlined.roundedCornersDefault) } @@ -474,41 +563,53 @@ // Test the values of the class properties. XCTAssertEqual(MDCTextInputControllerUnderline.errorColorDefault, MDCPalette.red.accent400) - XCTAssertEqual(MDCTextInputControllerUnderline.inlinePlaceholderColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault, false) - XCTAssertEqual(MDCTextInputControllerUnderline.activeColorDefault, - MDCPalette.blue.accent700) + XCTAssertEqual( + MDCTextInputControllerUnderline.inlinePlaceholderColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault, false) + XCTAssertEqual( + MDCTextInputControllerUnderline.activeColorDefault, + MDCPalette.blue.accent700) XCTAssertEqual(MDCTextInputControllerUnderline.normalColorDefault, .lightGray) XCTAssertEqual(MDCTextInputControllerUnderline.underlineHeightActiveDefault, 2) XCTAssertEqual(MDCTextInputControllerUnderline.underlineHeightNormalDefault, 1) XCTAssertEqual(MDCTextInputControllerUnderline.underlineViewModeDefault, .whileEditing) - XCTAssertEqual(MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault, - MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) - XCTAssertEqual(MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault, - MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) + XCTAssertEqual( + MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault, + MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) + XCTAssertEqual( + MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault, + MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) - XCTAssertEqual(MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) - XCTAssertEqual(MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault, - MDCTextInputControllerUnderline.trailingUnderlineLabelFontDefault) - XCTAssertEqual(MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) + XCTAssertEqual( + MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) + XCTAssertEqual( + MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault, + MDCTextInputControllerUnderline.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) // Default specific properties - XCTAssertEqual(MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault, - MDCTextInputControllerUnderline.activeColorDefault) + XCTAssertEqual( + MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault, + MDCTextInputControllerUnderline.activeColorDefault) - XCTAssertEqual(MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) XCTAssertEqual(Float(MDCTextInputControllerUnderline.floatingPlaceholderScaleDefault), 0.75) XCTAssertEqual(MDCTextInputControllerUnderline.isFloatingEnabledDefault, true) XCTAssertEqual(MDCTextInputControllerUnderline.roundedCornersDefault, []) - + XCTAssertNil(MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault) // Test the use of the class properties. @@ -516,40 +617,55 @@ var controller = MDCTextInputControllerUnderline(textInput: textField) XCTAssertEqual(controller.errorColor, MDCTextInputControllerUnderline.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerUnderline.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerUnderline.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerUnderline.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerUnderline.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerUnderline.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerUnderline.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerUnderline.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerUnderline.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerUnderline.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerUnderline.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerUnderline.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerUnderline.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerUnderline.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerUnderline.trailingUnderlineLabelFontDefault) // Default specific properties - XCTAssertEqual(controller.floatingPlaceholderActiveColor, - MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderActiveColor, + MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault) - XCTAssertEqual(controller.floatingPlaceholderNormalColor, - MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault) - XCTAssertEqual(controller.isFloatingEnabled, - MDCTextInputControllerUnderline.isFloatingEnabledDefault) + XCTAssertEqual( + controller.floatingPlaceholderNormalColor, + MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault) + XCTAssertEqual( + controller.isFloatingEnabled, + MDCTextInputControllerUnderline.isFloatingEnabledDefault) XCTAssertEqual(controller.roundedCorners, MDCTextInputControllerUnderline.roundedCornersDefault) // Test the changes to the class properties. @@ -560,8 +676,9 @@ XCTAssertEqual(MDCTextInputControllerUnderline.inlinePlaceholderColorDefault, .orange) MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault = false - XCTAssertEqual(MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault, - false) + XCTAssertEqual( + MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault, + false) MDCTextInputControllerUnderline.activeColorDefault = .purple XCTAssertEqual(MDCTextInputControllerUnderline.activeColorDefault, .purple) @@ -585,16 +702,19 @@ XCTAssertEqual(MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault, .white) MDCTextInputControllerUnderline.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 4) - XCTAssertEqual(MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 4)) + XCTAssertEqual( + MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 4)) MDCTextInputControllerUnderline.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 5) - XCTAssertEqual(MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 5)) + XCTAssertEqual( + MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 5)) MDCTextInputControllerUnderline.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 6) - XCTAssertEqual(MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 6)) + XCTAssertEqual( + MDCTextInputControllerUnderline.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 6)) // Default specific properties MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault = .red @@ -616,40 +736,55 @@ controller = MDCTextInputControllerUnderline(textInput: textField) XCTAssertEqual(controller.errorColor, MDCTextInputControllerUnderline.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerUnderline.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerUnderline.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerUnderline.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerUnderline.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerUnderline.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerUnderline.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerUnderline.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerUnderline.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerUnderline.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerUnderline.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerUnderline.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerUnderline.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerUnderline.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerUnderline.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerUnderline.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerUnderline.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerUnderline.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerUnderline.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerUnderline.trailingUnderlineLabelFontDefault) // Default specific properties - XCTAssertEqual(controller.floatingPlaceholderActiveColor, - MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault) + XCTAssertEqual( + controller.floatingPlaceholderActiveColor, + MDCTextInputControllerUnderline.floatingPlaceholderActiveColorDefault) - XCTAssertEqual(controller.floatingPlaceholderNormalColor, - MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault) - XCTAssertEqual(controller.isFloatingEnabled, - MDCTextInputControllerUnderline.isFloatingEnabledDefault) + XCTAssertEqual( + controller.floatingPlaceholderNormalColor, + MDCTextInputControllerUnderline.floatingPlaceholderNormalColorDefault) + XCTAssertEqual( + controller.isFloatingEnabled, + MDCTextInputControllerUnderline.isFloatingEnabledDefault) XCTAssertEqual(controller.roundedCorners, MDCTextInputControllerUnderline.roundedCornersDefault) } @@ -657,26 +792,32 @@ // Test the values of the class properties. XCTAssertEqual(MDCTextInputControllerFullWidth.disabledColorDefault, .clear) XCTAssertEqual(MDCTextInputControllerFullWidth.errorColorDefault, MDCPalette.red.accent400) - XCTAssertEqual(MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault, - false) + XCTAssertEqual( + MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault, + false) XCTAssertEqual(MDCTextInputControllerFullWidth.activeColorDefault, .clear) XCTAssertEqual(MDCTextInputControllerFullWidth.normalColorDefault, .clear) XCTAssertEqual(MDCTextInputControllerFullWidth.underlineHeightActiveDefault, 0) XCTAssertEqual(MDCTextInputControllerFullWidth.underlineHeightNormalDefault, 0) XCTAssertEqual(MDCTextInputControllerFullWidth.underlineViewModeDefault, .never) XCTAssertEqual(MDCTextInputControllerFullWidth.leadingUnderlineLabelTextColorDefault, .clear) - XCTAssertEqual(MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault, - UIColor(white: 0, alpha: CGFloat(0.54))) + XCTAssertEqual( + MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault, + UIColor(white: 0, alpha: CGFloat(0.54))) - XCTAssertEqual(MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) - XCTAssertEqual(MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault, - MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault) - XCTAssertEqual(MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault, - UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) - + XCTAssertEqual( + MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .body1)) + XCTAssertEqual( + MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault, + MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault, + UIFont.mdc_standardFont(forMaterialTextStyle: .caption)) + XCTAssertNil(MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) // Test the use of the class properties. @@ -685,31 +826,43 @@ XCTAssertEqual(controller.disabledColor, .clear) XCTAssertEqual(controller.errorColor, MDCTextInputControllerFullWidth.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerFullWidth.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerFullWidth.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerFullWidth.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerFullWidth.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerFullWidth.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerFullWidth.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerFullWidth.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerFullWidth.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerFullWidth.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerFullWidth.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerFullWidth.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerFullWidth.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault) // Test the changes to the class properties. MDCTextInputControllerFullWidth.disabledColorDefault = .red @@ -722,8 +875,9 @@ XCTAssertEqual(MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault, .orange) MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault = false - XCTAssertEqual(MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault, - false) + XCTAssertEqual( + MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault, + false) MDCTextInputControllerFullWidth.activeColorDefault = .purple XCTAssertEqual(MDCTextInputControllerFullWidth.activeColorDefault, .clear) @@ -747,47 +901,62 @@ XCTAssertEqual(MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault, .cyan) MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 4) - XCTAssertEqual(MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 4)) + XCTAssertEqual( + MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 4)) MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 5) - XCTAssertEqual(MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 5)) + XCTAssertEqual( + MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 5)) MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault = UIFont.systemFont(ofSize: 6) - XCTAssertEqual(MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, - UIFont.systemFont(ofSize: 6)) + XCTAssertEqual( + MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault, + UIFont.systemFont(ofSize: 6)) // Test the changes to the class properties can propagate to an instance. controller = MDCTextInputControllerFullWidth(textInput: textField) XCTAssertEqual(controller.disabledColor, .clear) XCTAssertEqual(controller.errorColor, MDCTextInputControllerFullWidth.errorColorDefault) - XCTAssertEqual(controller.inlinePlaceholderColor, - MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault) - XCTAssertEqual(controller.mdc_adjustsFontForContentSizeCategory, - MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault) - XCTAssertEqual(controller.activeColor, - MDCTextInputControllerFullWidth.activeColorDefault) - XCTAssertEqual(controller.normalColor, - MDCTextInputControllerFullWidth.normalColorDefault) - XCTAssertEqual(controller.underlineHeightActive, - MDCTextInputControllerFullWidth.underlineHeightActiveDefault) - XCTAssertEqual(controller.underlineHeightNormal, - MDCTextInputControllerFullWidth.underlineHeightNormalDefault) - XCTAssertEqual(controller.underlineViewMode, - MDCTextInputControllerFullWidth.underlineViewModeDefault) - XCTAssertEqual(controller.leadingUnderlineLabelTextColor, - MDCTextInputControllerFullWidth.leadingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.trailingUnderlineLabelTextColor, - MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.inlinePlaceholderColor, + MDCTextInputControllerFullWidth.inlinePlaceholderColorDefault) + XCTAssertEqual( + controller.mdc_adjustsFontForContentSizeCategory, + MDCTextInputControllerFullWidth.mdc_adjustsFontForContentSizeCategoryDefault) + XCTAssertEqual( + controller.activeColor, + MDCTextInputControllerFullWidth.activeColorDefault) + XCTAssertEqual( + controller.normalColor, + MDCTextInputControllerFullWidth.normalColorDefault) + XCTAssertEqual( + controller.underlineHeightActive, + MDCTextInputControllerFullWidth.underlineHeightActiveDefault) + XCTAssertEqual( + controller.underlineHeightNormal, + MDCTextInputControllerFullWidth.underlineHeightNormalDefault) + XCTAssertEqual( + controller.underlineViewMode, + MDCTextInputControllerFullWidth.underlineViewModeDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelTextColor, + MDCTextInputControllerFullWidth.leadingUnderlineLabelTextColorDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelTextColor, + MDCTextInputControllerFullWidth.trailingUnderlineLabelTextColorDefault) - XCTAssertEqual(controller.inlinePlaceholderFont, - MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault) - XCTAssertEqual(controller.leadingUnderlineLabelFont, - MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault) - XCTAssertEqual(controller.trailingUnderlineLabelFont, - MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.inlinePlaceholderFont, + MDCTextInputControllerFullWidth.inlinePlaceholderFontDefault) + XCTAssertEqual( + controller.leadingUnderlineLabelFont, + MDCTextInputControllerFullWidth.leadingUnderlineLabelFontDefault) + XCTAssertEqual( + controller.trailingUnderlineLabelFont, + MDCTextInputControllerFullWidth.trailingUnderlineLabelFontDefault) } // MARK: - textInputClearButtonTintColor @@ -801,8 +970,9 @@ let controllerFilled = MDCTextInputControllerFilled(textInput: textInput) // Then - XCTAssertEqual(controllerFilled.textInputClearButtonTintColor, - MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) + XCTAssertEqual( + controllerFilled.textInputClearButtonTintColor, + MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) } func testFilledTextInputClearButtonTintColorDefaultAppliesToTextField() { @@ -814,8 +984,9 @@ let _ = MDCTextInputControllerFilled(textInput: textInputFilled) // Then - XCTAssertEqual(textInputFilled.clearButton.tintColor, - MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) + XCTAssertEqual( + textInputFilled.clearButton.tintColor, + MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) } func testFilledTextInputClearButtonTintColorAppliesToTextField() { @@ -827,8 +998,9 @@ controllerFilled.textInputClearButtonTintColor = .black // Then - XCTAssertEqual(textInputFilled.clearButton.tintColor, - controllerFilled.textInputClearButtonTintColor) + XCTAssertEqual( + textInputFilled.clearButton.tintColor, + controllerFilled.textInputClearButtonTintColor) } func testOutlinedTextInputClearButtonTintColorUsesDefault() { @@ -840,8 +1012,9 @@ let controllerOutlined = MDCTextInputControllerOutlined(textInput: textInput) // Then - XCTAssertEqual(controllerOutlined.textInputClearButtonTintColor, - MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) + XCTAssertEqual( + controllerOutlined.textInputClearButtonTintColor, + MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) } func testOutlinedTextInputClearButtonTintColorDefaultAppliesToTextField() { @@ -853,8 +1026,9 @@ let _ = MDCTextInputControllerOutlined(textInput: textInputOutlined) // Then - XCTAssertEqual(textInputOutlined.clearButton.tintColor, - MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) + XCTAssertEqual( + textInputOutlined.clearButton.tintColor, + MDCTextInputControllerFilled.textInputClearButtonTintColorDefault) } func testOutlinedTextInputClearButtonTintColorAppliesToTextField() { @@ -866,85 +1040,92 @@ controllerOutlined.textInputClearButtonTintColor = .red // Then - XCTAssertEqual(textInputOutlined.clearButton.tintColor, - controllerOutlined.textInputClearButtonTintColor) + XCTAssertEqual( + textInputOutlined.clearButton.tintColor, + controllerOutlined.textInputClearButtonTintColor) } - + func testUnderlineTextInputClearButtonTintColorUsesDefault() { // Given MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault = .orange - + // When let textInput = MDCTextField() let controllerUnderline = MDCTextInputControllerUnderline(textInput: textInput) - + // Then - XCTAssertEqual(controllerUnderline.textInputClearButtonTintColor, - MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault) + XCTAssertEqual( + controllerUnderline.textInputClearButtonTintColor, + MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault) } - + func testUnderlineTextInputClearButtonTintColorDefaultAppliesToTextField() { // Given MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault = .orange - + // When let textInputUnderline = MDCTextField() let _ = MDCTextInputControllerUnderline(textInput: textInputUnderline) - + // Then - XCTAssertEqual(textInputUnderline.clearButton.tintColor, - MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault) + XCTAssertEqual( + textInputUnderline.clearButton.tintColor, + MDCTextInputControllerUnderline.textInputClearButtonTintColorDefault) } - + func testUnderlineTextInputClearButtonTintColorAppliesToTextField() { // Given let textInputUnderline = MDCTextField() let controllerUnderline = MDCTextInputControllerUnderline(textInput: textInputUnderline) - + // When controllerUnderline.textInputClearButtonTintColor = .black - + // Then - XCTAssertEqual(textInputUnderline.clearButton.tintColor, - controllerUnderline.textInputClearButtonTintColor) + XCTAssertEqual( + textInputUnderline.clearButton.tintColor, + controllerUnderline.textInputClearButtonTintColor) } - + func testFullWidthTextInputClearButtonTintColorUsesDefault() { // Given MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault = .orange - + // When let textInput = MDCTextField() let controllerFullWidth = MDCTextInputControllerFullWidth(textInput: textInput) - + // Then - XCTAssertEqual(controllerFullWidth.textInputClearButtonTintColor, - MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault) + XCTAssertEqual( + controllerFullWidth.textInputClearButtonTintColor, + MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault) } - + func testFullWidthTextInputClearButtonTintColorDefaultAppliesToTextField() { // Given MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault = .orange - + // When let textInputFullWidth = MDCTextField() let _ = MDCTextInputControllerFullWidth(textInput: textInputFullWidth) - + // Then - XCTAssertEqual(textInputFullWidth.clearButton.tintColor, - MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault) + XCTAssertEqual( + textInputFullWidth.clearButton.tintColor, + MDCTextInputControllerFullWidth.textInputClearButtonTintColorDefault) } - + func testFullWidthTextInputClearButtonTintColorAppliesToTextField() { // Given let textInputFullWidth = MDCTextField() let controllerFullWidth = MDCTextInputControllerFullWidth(textInput: textInputFullWidth) - + // When controllerFullWidth.textInputClearButtonTintColor = .black - + // Then - XCTAssertEqual(textInputFullWidth.clearButton.tintColor, - controllerFullWidth.textInputClearButtonTintColor) + XCTAssertEqual( + textInputFullWidth.clearButton.tintColor, + controllerFullWidth.textInputClearButtonTintColor) } }
diff --git a/components/TextFields/tests/unit/Theming/TextFieldsMaterialThemingTests.swift b/components/TextFields/tests/unit/TextFieldsMaterialThemingTests.swift similarity index 100% rename from components/TextFields/tests/unit/Theming/TextFieldsMaterialThemingTests.swift rename to components/TextFields/tests/unit/TextFieldsMaterialThemingTests.swift
diff --git a/components/Tooltips/.jazzy.yaml b/components/Tooltips/.jazzy.yaml deleted file mode 100644 index b5a8cb9..0000000 --- a/components/Tooltips/.jazzy.yaml +++ /dev/null
@@ -1,6 +0,0 @@ -# Auto-generated by scripts/generate_jazzy_yamls.sh. Used primarily by scripts/external/arc-jazzy-linter. -module: Tooltips -umbrella_header: src/MaterialTooltips.h -objc: true -sdk: iphonesimulator -framework_root: ../
diff --git a/components/Tooltips/README.md b/components/Tooltips/README.md deleted file mode 100644 index b620788..0000000 --- a/components/Tooltips/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -# Tooltips - -The [Tooltips component](https://material.io/go/design-tooltips) is yet to be completed, please follow the [tracking issue](https://www.pivotaltracker.com/epic/show/3954823) for more information. -
diff --git a/components/Typography/README.md b/components/Typography/README.md index ddd94d0..494ff9b 100644 --- a/components/Typography/README.md +++ b/components/Typography/README.md
@@ -290,7 +290,7 @@ Users configure text styles in source code. First, you call the `scalerForMaterialTextStyle:` method. This method returns an `MDCFontScalar` object for a given `MDCFontTextStyle`. Next, use the `MDCFontScalar` object to scale a `UIFont` by calling `scaledFontWithFont:` method. This method scales the font based on Dynamic Type setting provided by the user. This method also supports both system fonts and custom fonts. -##### Objective-C +#### Objective-C ```objc UIFont *customFont = [UIFont fontWithName:@"CustomFontName" size:18.0]; @@ -299,7 +299,7 @@ label.font = customScalingFont; ``` -##### Swift +#### Swift ```swift let customFont = UIFont(name: "CustomFontName", size: 18.0)!
diff --git a/components/Typography/docs/dynamic-type.md b/components/Typography/docs/dynamic-type.md index 59399a6..ed2a5e6 100644 --- a/components/Typography/docs/dynamic-type.md +++ b/components/Typography/docs/dynamic-type.md
@@ -12,7 +12,7 @@ Users configure text styles in source code. First, you call the `scalerForMaterialTextStyle:` method. This method returns an `MDCFontScalar` object for a given `MDCFontTextStyle`. Next, use the `MDCFontScalar` object to scale a `UIFont` by calling `scaledFontWithFont:` method. This method scales the font based on Dynamic Type setting provided by the user. This method also supports both system fonts and custom fonts. -##### Objective-C +#### Objective-C ```objc UIFont *customFont = [UIFont fontWithName:@"CustomFontName" size:18.0]; @@ -21,7 +21,7 @@ label.font = customScalingFont; ``` -##### Swift +#### Swift ```swift let customFont = UIFont(name: "CustomFontName", size: 18.0)!
diff --git a/components/Typography/src/MDCFontScaler.h b/components/Typography/src/MDCFontScaler.h index 6489429..c1c6905 100644 --- a/components/Typography/src/MDCFontScaler.h +++ b/components/Typography/src/MDCFontScaler.h
@@ -77,19 +77,4 @@ */ - (nonnull UIFont *)scaledFontWithFont:(nonnull UIFont *)font; -/** - Scales an arbitrary value based on the current Dynamic Type settings and the scaling curve. - - This method calculates the current scale factor and multiplies it by the given value. - - As an example, assume the metrics value for @c .Large is 12 and the current @c - UIContentCategorySize is - @c .ExtraLarge with a metrics value of 24. When passed a @c value of 10, expect a return - value of 20. - - @param value The original layout value. - @return A value that has been scaled based on the attached scaling curve - */ -- (CGFloat)scaledValueForValue:(CGFloat)value; - @end
diff --git a/components/Typography/src/MDCFontScaler.m b/components/Typography/src/MDCFontScaler.m index dae11f0..9da0813 100644 --- a/components/Typography/src/MDCFontScaler.m +++ b/components/Typography/src/MDCFontScaler.m
@@ -280,30 +280,6 @@ return scaledFont; } -- (CGFloat)scaledValueForValue:(CGFloat)value { - UIContentSizeCategory defaultSizeCategory = UIContentSizeCategoryLarge; - // If it is available, query the preferredContentSizeCategory. - UIContentSizeCategory currentSizeCategory = GetCurrentSizeCategory(); - - NSNumber *defaultFontSizeNumber = _scalingCurve[defaultSizeCategory]; - NSNumber *currentFontSizeNumber = _scalingCurve[currentSizeCategory]; - - // Guard against broken / incomplete scaling curves by returning self if fontSizeNumber is nil. - if (currentFontSizeNumber == nil || defaultFontSizeNumber == nil) { - return value; - } - - CGFloat currentFontSize = (CGFloat)currentFontSizeNumber.doubleValue; - CGFloat defaultFontSize = (CGFloat)defaultFontSizeNumber.doubleValue; - - // Guard against broken / incomplete scaling curves by returning self if fontSize <= 0.0. - if (currentFontSize <= 0.0 || defaultFontSize <= 0.0) { - return value; - } - - return (currentFontSize / defaultFontSize) * value; -} - - (NSString *)description { NSString *superDescription = [super description]; NSString *styleDescription = @"No Attached Style";
diff --git a/components/Typography/src/UIFont+MaterialScalable.h b/components/Typography/src/UIFont+MaterialScalable.h index ca55284..f432bf1 100644 --- a/components/Typography/src/UIFont+MaterialScalable.h +++ b/components/Typography/src/UIFont+MaterialScalable.h
@@ -50,13 +50,6 @@ Returns a font with the same family, weight and traits, but whose point size is based on the given trait environment's preferred content size category. - If the device is running iOS 9 and not in an extension, then the provided traitEnvironment will be - ignored and the UIApplication sharedApplication's preferredContentSizeCategory will be used - instead. - - If the device is running iOS 9 and in an extension, then the provided trait environment will be - ignored and the returned font will be scaled with UIContentSizeCategoryLarge. - @param traitEnvironment The trait environment whose trait collection should be queried. @return A font whose point size is determined by @c mdc_scalingCurve for the given trait environment's content size category, or self if @c mdc_scalingCurve is nil.
diff --git a/components/Typography/src/UIFont+MaterialScalable.m b/components/Typography/src/UIFont+MaterialScalable.m index 921e0db..5480530 100644 --- a/components/Typography/src/UIFont+MaterialScalable.m +++ b/components/Typography/src/UIFont+MaterialScalable.m
@@ -58,12 +58,8 @@ } - (UIFont *)mdc_scaledFontForTraitEnvironment:(id<UITraitEnvironment>)traitEnvironment { - UIContentSizeCategory sizeCategory = UIContentSizeCategoryLarge; - if (@available(iOS 10.0, *)) { - sizeCategory = traitEnvironment.traitCollection.preferredContentSizeCategory; - } else if ([UIApplication mdc_safeSharedApplication]) { - sizeCategory = [UIApplication mdc_safeSharedApplication].preferredContentSizeCategory; - } + UIContentSizeCategory sizeCategory = + traitEnvironment.traitCollection.preferredContentSizeCategory; return [self mdc_scaledFontForSizeCategory:sizeCategory]; }
diff --git a/components/Typography/src/UIFontDescriptor+MaterialTypography.m b/components/Typography/src/UIFontDescriptor+MaterialTypography.m index c925b48..7c86c4b 100644 --- a/components/Typography/src/UIFontDescriptor+MaterialTypography.m +++ b/components/Typography/src/UIFontDescriptor+MaterialTypography.m
@@ -64,7 +64,7 @@ // If we are within an application, query the preferredContentSizeCategory. if ([UIApplication mdc_safeSharedApplication]) { sizeCategory = [UIApplication mdc_safeSharedApplication].preferredContentSizeCategory; - } else if (@available(iOS 10.0, *)) { + } else { sizeCategory = UIScreen.mainScreen.traitCollection.preferredContentSizeCategory; }
diff --git a/components/Typography/src/private/MDCTypographyUtilities.m b/components/Typography/src/private/MDCTypographyUtilities.m index f84d529..4210d67 100644 --- a/components/Typography/src/private/MDCTypographyUtilities.m +++ b/components/Typography/src/private/MDCTypographyUtilities.m
@@ -21,12 +21,5 @@ if we are unable to query the device due to being in an extension. */ UIContentSizeCategory GetCurrentSizeCategory(void) { - UIContentSizeCategory sizeCategory = UIContentSizeCategoryLarge; - if (@available(iOS 10.0, *)) { - sizeCategory = UIScreen.mainScreen.traitCollection.preferredContentSizeCategory; - } else if ([UIApplication mdc_safeSharedApplication]) { - sizeCategory = [UIApplication mdc_safeSharedApplication].preferredContentSizeCategory; - } - - return sizeCategory; + return UIScreen.mainScreen.traitCollection.preferredContentSizeCategory; }
diff --git a/components/private/Color/tests/unit/MaterialColorTests.m b/components/private/Color/tests/unit/MaterialColorTests.m index 784d132..a734e29 100644 --- a/components/private/Color/tests/unit/MaterialColorTests.m +++ b/components/private/Color/tests/unit/MaterialColorTests.m
@@ -15,9 +15,9 @@ #import <XCTest/XCTest.h> #import "MaterialAvailability.h" -#import "MaterialMath.h" #import "UIColor+MaterialBlending.h" #import "UIColor+MaterialDynamic.h" +#import "MaterialMath.h" /** Returns a generated image of the given color and bounds. */ static UIImage *fakeImageWithColorAndSize(UIColor *color, CGRect bounds) { @@ -244,42 +244,38 @@ } - (void)testP3ColorMergeTest { - if (@available(iOS 10.0, *)) { - UIColor *backgroundColor = [UIColor colorWithWhite:(CGFloat)0.3 alpha:(CGFloat)0.8]; - UIColor *blendColor = [UIColor colorWithRed:(CGFloat)0.9 - green:(CGFloat)0.82 - blue:(CGFloat)0.1 - alpha:(CGFloat)0.6]; - UIColor *expectedColor = [UIColor colorWithRed:(CGFloat)0.69130434782608696 - green:(CGFloat)0.63913043478260867 - blue:(CGFloat)0.16956521739130434 - alpha:(CGFloat)0.92000000000000004]; - UIColor *resultColor = [UIColor mdc_blendColor:blendColor withBackgroundColor:backgroundColor]; - XCTAssertTrue([self compareColorsWithFloatPrecisionFirstColor:resultColor - secondColor:expectedColor]); - } + UIColor *backgroundColor = [UIColor colorWithWhite:(CGFloat)0.3 alpha:(CGFloat)0.8]; + UIColor *blendColor = [UIColor colorWithRed:(CGFloat)0.9 + green:(CGFloat)0.82 + blue:(CGFloat)0.1 + alpha:(CGFloat)0.6]; + UIColor *expectedColor = [UIColor colorWithRed:(CGFloat)0.69130434782608696 + green:(CGFloat)0.63913043478260867 + blue:(CGFloat)0.16956521739130434 + alpha:(CGFloat)0.92000000000000004]; + UIColor *resultColor = [UIColor mdc_blendColor:blendColor withBackgroundColor:backgroundColor]; + XCTAssertTrue([self compareColorsWithFloatPrecisionFirstColor:resultColor + secondColor:expectedColor]); } - (void)testColorWithPatternImageMergeTest { - if (@available(iOS 10.0, *)) { - UIColor *backgroundColor = [UIColor colorWithHue:(CGFloat)0.7 - saturation:(CGFloat)0.6 - brightness:(CGFloat)0.2 - alpha:(CGFloat)0.7]; - UIColor *imageColor = [UIColor colorWithRed:(CGFloat)0.3 - green:(CGFloat)0.3 - blue:(CGFloat)0.2 - alpha:(CGFloat)0.8]; - UIImage *fakeImage = fakeImageWithColorAndSize(imageColor, CGRectMake(0, 0, 100, 100)); - UIColor *blendColor = [UIColor colorWithPatternImage:fakeImage]; - UIColor *expectedColor = [UIColor colorWithRed:(CGFloat)0.10399999999999993 - green:(CGFloat)0.080000000000000016 - blue:(CGFloat)0.19999999999999998 - alpha:(CGFloat)0.69999999999999996]; - UIColor *resultColor = [UIColor mdc_blendColor:blendColor withBackgroundColor:backgroundColor]; - XCTAssertTrue([self compareColorsWithFloatPrecisionFirstColor:resultColor - secondColor:expectedColor]); - } + UIColor *backgroundColor = [UIColor colorWithHue:(CGFloat)0.7 + saturation:(CGFloat)0.6 + brightness:(CGFloat)0.2 + alpha:(CGFloat)0.7]; + UIColor *imageColor = [UIColor colorWithRed:(CGFloat)0.3 + green:(CGFloat)0.3 + blue:(CGFloat)0.2 + alpha:(CGFloat)0.8]; + UIImage *fakeImage = fakeImageWithColorAndSize(imageColor, CGRectMake(0, 0, 100, 100)); + UIColor *blendColor = [UIColor colorWithPatternImage:fakeImage]; + UIColor *expectedColor = [UIColor colorWithRed:(CGFloat)0.10399999999999993 + green:(CGFloat)0.080000000000000016 + blue:(CGFloat)0.19999999999999998 + alpha:(CGFloat)0.69999999999999996]; + UIColor *resultColor = [UIColor mdc_blendColor:blendColor withBackgroundColor:backgroundColor]; + XCTAssertTrue([self compareColorsWithFloatPrecisionFirstColor:resultColor + secondColor:expectedColor]); } - (void)testResolvedColorForPreiOS13ResultsInSameColor {
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControl.h b/components/private/TextControlsPrivate/src/Shared/MDCTextControl.h index 69bb549..dfb100c 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControl.h +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControl.h
@@ -21,7 +21,7 @@ #import "MDCTextControlColorViewModel.h" #import "MDCTextControlHorizontalPositioningReference.h" #import "MDCTextControlLabelAnimation.h" -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" #import "MDCTextControlVerticalPositioningReference.h" UIFont *_Nonnull MDCTextControlDefaultUITextFieldFont(void);
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.h b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.h index 6f9cc9b..62727a0 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.h +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.h
@@ -14,7 +14,7 @@ #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" /** The logic to animate labels is extracted into its own class so that any MDCTextControl can @@ -31,11 +31,12 @@ no animation in progress. */ + (void)animateLabel:(nonnull UILabel *)label - state:(MDCTextControlLabelPosition)labelPosition - normalLabelFrame:(CGRect)normalLabelFrame - floatingLabelFrame:(CGRect)floatingLabelFrame - normalFont:(nonnull UIFont *)normalFont - floatingFont:(nonnull UIFont *)floatingFont - animationDuration:(NSTimeInterval)animationDuration - completion:(void (^__nullable)(BOOL))completion; + state:(MDCTextControlLabelPosition)labelPosition + normalLabelFrame:(CGRect)normalLabelFrame + floatingLabelFrame:(CGRect)floatingLabelFrame + normalFont:(nonnull UIFont *)normalFont + floatingFont:(nonnull UIFont *)floatingFont + labelTruncationIsPresent:(BOOL)labelTruncationIsPresent + animationDuration:(NSTimeInterval)animationDuration + completion:(void (^__nullable)(BOOL))completion; @end
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.m b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.m index ee959ba..15cf217 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.m +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelAnimation.m
@@ -15,18 +15,19 @@ #import "MDCTextControlLabelAnimation.h" #import "MaterialAnimationTiming.h" -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" @implementation MDCTextControlLabelAnimation + (void)animateLabel:(nonnull UILabel *)label - state:(MDCTextControlLabelPosition)labelPosition - normalLabelFrame:(CGRect)normalLabelFrame - floatingLabelFrame:(CGRect)floatingLabelFrame - normalFont:(nonnull UIFont *)normalFont - floatingFont:(nonnull UIFont *)floatingFont - animationDuration:(NSTimeInterval)animationDuration - completion:(void (^__nullable)(BOOL))completion { + state:(MDCTextControlLabelPosition)labelPosition + normalLabelFrame:(CGRect)normalLabelFrame + floatingLabelFrame:(CGRect)floatingLabelFrame + normalFont:(nonnull UIFont *)normalFont + floatingFont:(nonnull UIFont *)floatingFont + labelTruncationIsPresent:(BOOL)labelTruncationIsPresent + animationDuration:(NSTimeInterval)animationDuration + completion:(void (^__nullable)(BOOL))completion { BOOL isAnimationInProgress = label.layer.animationKeys.count > 0; if (isAnimationInProgress) { if (completion) { @@ -53,7 +54,7 @@ BOOL currentFrameIsCGRectZero = CGRectEqualToRect(currentFrame, CGRectZero); BOOL isNormalTransition = willChangeFrame && !currentFrameIsCGRectZero; BOOL nonZeroDuration = animationDuration > 0; - BOOL shouldPerformAnimation = nonZeroDuration && isNormalTransition; + BOOL shouldPerformAnimation = nonZeroDuration && isNormalTransition && !labelTruncationIsPresent; void (^completionBlock)(BOOL finished) = ^void(BOOL finished) { label.transform = CGAffineTransformIdentity;
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelPosition.h b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelSupport.h similarity index 70% rename from components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelPosition.h rename to components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelSupport.h index b98cc02..28f2932 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelPosition.h +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelSupport.h
@@ -15,24 +15,24 @@ #import <UIKit/UIKit.h> /** - This enum represents different states the floating label can be in. + This enum represents different positional states the label can be in. */ typedef NS_ENUM(NSUInteger, MDCTextControlLabelPosition) { /** - The state where the floating label is not visible. + The state where the label is not visible. */ MDCTextControlLabelPositionNone, /** - The state where the floating label is floating. + The state where the label is positioned (i.e. floating) above the text rect. */ MDCTextControlLabelPositionFloating, /** - The state where the floating label is occupying the normal text area. + The state where the label is positioned in the normal text area. */ MDCTextControlLabelPositionNormal, }; -MDCTextControlLabelPosition MDCTextControlLabelPositionWith(BOOL hasLabelText, - BOOL hasText, - BOOL canLabelFloat, - BOOL isEditing); +MDCTextControlLabelPosition MDCTextControlLabelPositionWith(BOOL hasLabelText, BOOL hasText, + BOOL canLabelFloat, BOOL isEditing); + +CGSize MDCTextControlLabelSizeWith(NSString *text, CGFloat maxWidth, UIFont *font);
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelPosition.m b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelSupport.m similarity index 69% rename from components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelPosition.m rename to components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelSupport.m index 977462d..bac04b1 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelPosition.m +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlLabelSupport.m
@@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" #import <UIKit/UIKit.h> -MDCTextControlLabelPosition MDCTextControlLabelPositionWith(BOOL hasLabelText, - BOOL hasText, - BOOL canLabelFloat, - BOOL isEditing) { +MDCTextControlLabelPosition MDCTextControlLabelPositionWith(BOOL hasLabelText, BOOL hasText, + BOOL canLabelFloat, BOOL isEditing) { if (hasLabelText) { if (canLabelFloat) { if (isEditing) { @@ -45,3 +43,16 @@ return MDCTextControlLabelPositionNone; } } + +CGSize MDCTextControlLabelSizeWith(NSString *text, CGFloat maxWidth, UIFont *font) { + if (!font) { + return CGSizeZero; + } + CGSize fittingSize = CGSizeMake(maxWidth, CGFLOAT_MAX); + NSDictionary *attributes = @{NSFontAttributeName : font}; + CGRect rect = [text boundingRectWithSize:fittingSize + options:NSStringDrawingUsesLineFragmentOrigin + attributes:attributes + context:nil]; + return rect.size; +}
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.h b/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.h index 86663da..b239a11 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.h +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.h
@@ -13,7 +13,7 @@ // limitations under the License. #import <UIKit/UIKit.h> -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" /** This method tells an MDCTextControl whether its placeholder should be visible.
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.m b/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.m index 53faa46..d1469af 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.m +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlPlaceholderSupport.m
@@ -16,7 +16,7 @@ #import <UIKit/UIKit.h> -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" BOOL MDCTextControlShouldPlaceholderBeVisibleWithPlaceholder( NSString *placeholder, NSString *text, MDCTextControlLabelPosition labelPosition) {
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlSideViewSupport.h b/components/private/TextControlsPrivate/src/Shared/MDCTextControlSideViewSupport.h index 71a16ea..9adf75a 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlSideViewSupport.h +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlSideViewSupport.h
@@ -13,7 +13,7 @@ // limitations under the License. #import <UIKit/UIKit.h> -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" /** This method tells an MDCTextControl whether to display a side view or not.
diff --git a/components/private/TextControlsPrivate/src/Shared/MDCTextControlVerticalPositioningReference.h b/components/private/TextControlsPrivate/src/Shared/MDCTextControlVerticalPositioningReference.h index 7322c35..2932aab 100644 --- a/components/private/TextControlsPrivate/src/Shared/MDCTextControlVerticalPositioningReference.h +++ b/components/private/TextControlsPrivate/src/Shared/MDCTextControlVerticalPositioningReference.h
@@ -16,7 +16,7 @@ #import <UIKit/UIKit.h> #import "MDCTextControlLabelBehavior.h" -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" /** Style objects vend objects conforming to this protocol to provide the MDCTextControl's layout
diff --git a/components/private/TextControlsPrivate/src/Shared/MaterialTextControlsPrivate+Shared.h b/components/private/TextControlsPrivate/src/Shared/MaterialTextControlsPrivate+Shared.h index b0cc02e..09f3cb8 100644 --- a/components/private/TextControlsPrivate/src/Shared/MaterialTextControlsPrivate+Shared.h +++ b/components/private/TextControlsPrivate/src/Shared/MaterialTextControlsPrivate+Shared.h
@@ -20,7 +20,7 @@ #import "MDCTextControlHorizontalPositioning.h" #import "MDCTextControlHorizontalPositioningReference.h" #import "MDCTextControlLabelAnimation.h" -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" #import "MDCTextControlPlaceholderSupport.h" #import "MDCTextControlSideViewSupport.h" #import "MDCTextControlVerticalPositioningReference.h"
diff --git a/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.h b/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.h index 8feaf12..ed28b18 100644 --- a/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.h +++ b/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.h
@@ -33,6 +33,7 @@ @property(nonatomic, readonly) CGFloat calculatedHeight; @property(nonatomic, assign) CGFloat containerHeight; +@property(nonatomic, assign) BOOL labelTruncationIsPresent; /** Initializing an MDCBaseTextFieldLayout object with this initializer is tantamount to calculating a
diff --git a/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.m b/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.m index 104d2bd..ee494ad 100644 --- a/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.m +++ b/components/private/TextControlsPrivate/src/TextFields/MDCBaseTextFieldLayout.m
@@ -15,6 +15,7 @@ #import "MDCBaseTextFieldLayout.h" #import "MaterialTextControlsPrivate+Shared.h" +#import "MDCTextControlTextFieldSideViewAlignment.h" @interface MDCBaseTextFieldLayout () @end @@ -230,20 +231,31 @@ CGRect clearButtonFrame = CGRectMake(clearButtonMinX, clearButtonMinY, clearButtonSideLength, clearButtonSideLength); - CGRect labelFrameNormal = [self labelFrameWithText:label.text - labelPosition:MDCTextControlLabelPositionNormal - font:font - floatingFont:floatingFont - floatingLabelMinY:floatingLabelMinY - textRect:textRectNormal - isRTL:isRTL]; - CGRect labelFrameFloating = [self labelFrameWithText:label.text - labelPosition:MDCTextControlLabelPositionFloating - font:font - floatingFont:floatingFont - floatingLabelMinY:floatingLabelMinY - textRect:textRectNormal - isRTL:isRTL]; + CGSize labelSizeNormal = MDCTextControlLabelSizeWith(label.text, textRectWidth, font); + CGSize labelSizeFloating = MDCTextControlLabelSizeWith(label.text, textRectWidth, floatingFont); + BOOL normalLabelWillTruncate = labelSizeNormal.height > font.lineHeight; + BOOL floatingLabelWillTruncate = labelSizeFloating.height > floatingFont.lineHeight; + if (normalLabelWillTruncate) { + labelSizeNormal.height = font.lineHeight; + labelSizeNormal.width = textRectWidth; + } + if (floatingLabelWillTruncate) { + labelSizeFloating.height = floatingFont.lineHeight; + labelSizeFloating.width = textRectWidth; + } + self.labelTruncationIsPresent = normalLabelWillTruncate || floatingLabelWillTruncate; + + CGRect labelFrameNormal = [self labelFrameWithLabelSize:labelSizeNormal + labelPosition:MDCTextControlLabelPositionNormal + floatingLabelMinY:floatingLabelMinY + textRect:textRectNormal + isRTL:isRTL]; + + CGRect labelFrameFloating = [self labelFrameWithLabelSize:labelSizeFloating + labelPosition:MDCTextControlLabelPositionFloating + floatingLabelMinY:floatingLabelMinY + textRect:textRectNormal + isRTL:isRTL]; self.assistiveLabelViewLayout = [[MDCTextControlAssistiveLabelViewLayout alloc] initWithWidth:textFieldWidth @@ -309,33 +321,14 @@ } } -- (CGSize)floatingLabelSizeWithText:(NSString *)placeholder - maxWidth:(CGFloat)maxWidth - font:(UIFont *)font { - if (!font) { - return CGSizeZero; - } - CGSize fittingSize = CGSizeMake(maxWidth, CGFLOAT_MAX); - NSDictionary *attributes = @{NSFontAttributeName : font}; - CGRect rect = [placeholder boundingRectWithSize:fittingSize - options:NSStringDrawingUsesLineFragmentOrigin - attributes:attributes - context:nil]; - rect.size.height = font.lineHeight; - return rect.size; -} - -- (CGRect)labelFrameWithText:(NSString *)text - labelPosition:(MDCTextControlLabelPosition)labelPosition - font:(UIFont *)font - floatingFont:(UIFont *)floatingFont - floatingLabelMinY:(CGFloat)floatingLabelMinY - textRect:(CGRect)textRect - isRTL:(BOOL)isRTL { +- (CGRect)labelFrameWithLabelSize:(CGSize)size + labelPosition:(MDCTextControlLabelPosition)labelPosition + floatingLabelMinY:(CGFloat)floatingLabelMinY + textRect:(CGRect)textRect + isRTL:(BOOL)isRTL { CGFloat labelMinX = CGRectGetMinX(textRect); CGFloat labelMaxX = CGRectGetMaxX(textRect); - CGFloat maxWidth = labelMaxX - labelMinX; - CGSize size = CGSizeZero; + CGFloat textRectMidY = CGRectGetMidY(textRect); CGRect rect = CGRectZero; CGFloat originX = 0; CGFloat originY = 0; @@ -343,7 +336,6 @@ case MDCTextControlLabelPositionNone: break; case MDCTextControlLabelPositionFloating: - size = [self floatingLabelSizeWithText:text maxWidth:maxWidth font:floatingFont]; originY = floatingLabelMinY; if (isRTL) { originX = labelMaxX - size.width; @@ -353,9 +345,7 @@ rect = CGRectMake(originX, originY, size.width, size.height); break; case MDCTextControlLabelPositionNormal: - size = [self floatingLabelSizeWithText:text maxWidth:maxWidth font:font]; - CGFloat textRectMidY = CGRectGetMidY(textRect); - originY = textRectMidY - ((CGFloat)0.5 * size.height); + originY = textRectMidY - (0.5f * size.height); if (isRTL) { originX = labelMaxX - size.width; } else {
diff --git a/components/private/TextControlsPrivate/tests/unit/TextFields/MDCBaseTextFieldLayoutTests.m b/components/private/TextControlsPrivate/tests/unit/MDCBaseTextFieldLayoutTests.m similarity index 98% rename from components/private/TextControlsPrivate/tests/unit/TextFields/MDCBaseTextFieldLayoutTests.m rename to components/private/TextControlsPrivate/tests/unit/MDCBaseTextFieldLayoutTests.m index 65c9d0c..2cbfa41 100644 --- a/components/private/TextControlsPrivate/tests/unit/TextFields/MDCBaseTextFieldLayoutTests.m +++ b/components/private/TextControlsPrivate/tests/unit/MDCBaseTextFieldLayoutTests.m
@@ -16,6 +16,7 @@ #import "MDCTextControlLabelBehavior.h" #import "MaterialTextControlsPrivate+BaseStyle.h" +#import "MDCTextControlAssistiveLabelDrawPriority.h" #import "MaterialTextControlsPrivate+Shared.h" #import "MaterialTextControlsPrivate+TextFields.h"
diff --git a/components/private/TextControlsPrivate/tests/unit/Shared/MDCTextControlPlaceholderSupportTests.m b/components/private/TextControlsPrivate/tests/unit/MDCTextControlPlaceholderSupportTests.m similarity index 97% rename from components/private/TextControlsPrivate/tests/unit/Shared/MDCTextControlPlaceholderSupportTests.m rename to components/private/TextControlsPrivate/tests/unit/MDCTextControlPlaceholderSupportTests.m index b403ae8..642a27f 100644 --- a/components/private/TextControlsPrivate/tests/unit/Shared/MDCTextControlPlaceholderSupportTests.m +++ b/components/private/TextControlsPrivate/tests/unit/MDCTextControlPlaceholderSupportTests.m
@@ -14,7 +14,7 @@ #import <XCTest/XCTest.h> -#import "MDCTextControlLabelPosition.h" +#import "MDCTextControlLabelSupport.h" #import "MDCTextControlPlaceholderSupport.h" @interface MDCTextControlPlaceholderSupportTests : XCTestCase
diff --git a/demos/Bare/Bare.xcodeproj/project.pbxproj b/demos/Bare/Bare.xcodeproj/project.pbxproj deleted file mode 100644 index 395c447..0000000 --- a/demos/Bare/Bare.xcodeproj/project.pbxproj +++ /dev/null
@@ -1,422 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 20AA6AA11D4A5D0C0062273A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 20AA6AA01D4A5D0C0062273A /* main.m */; }; - 20AA6AA41D4A5D0C0062273A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 20AA6AA31D4A5D0C0062273A /* AppDelegate.m */; }; - 20AA6AA71D4A5D0C0062273A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 20AA6AA61D4A5D0C0062273A /* ViewController.m */; }; - 20AA6AAA1D4A5D0C0062273A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 20AA6AA81D4A5D0C0062273A /* Main.storyboard */; }; - 20AA6AAC1D4A5D0C0062273A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 20AA6AAB1D4A5D0C0062273A /* Assets.xcassets */; }; - 20AA6AAF1D4A5D0C0062273A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 20AA6AAD1D4A5D0C0062273A /* LaunchScreen.storyboard */; }; - AA9FA499886AFC88AE704B07 /* libPods-Bare.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E2B1A09FCA98A759F2E2666B /* libPods-Bare.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 20AA6A9C1D4A5D0C0062273A /* Bare.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bare.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 20AA6AA01D4A5D0C0062273A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; - 20AA6AA21D4A5D0C0062273A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; - 20AA6AA31D4A5D0C0062273A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; - 20AA6AA51D4A5D0C0062273A /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; - 20AA6AA61D4A5D0C0062273A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; - 20AA6AA91D4A5D0C0062273A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; - 20AA6AAB1D4A5D0C0062273A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; - 20AA6AAE1D4A5D0C0062273A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; - 20AA6AB01D4A5D0C0062273A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; - 446F2F1AECCCB052B6006DEA /* Pods-Bare.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bare.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Bare/Pods-Bare.debug.xcconfig"; sourceTree = "<group>"; }; - E2B1A09FCA98A759F2E2666B /* libPods-Bare.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Bare.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - ED9C9E04E226DD8974E12F27 /* Pods-Bare.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bare.release.xcconfig"; path = "Pods/Target Support Files/Pods-Bare/Pods-Bare.release.xcconfig"; sourceTree = "<group>"; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 20AA6A991D4A5D0C0062273A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - AA9FA499886AFC88AE704B07 /* libPods-Bare.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 10E2F8C89368C139068A0B3E /* Frameworks */ = { - isa = PBXGroup; - children = ( - E2B1A09FCA98A759F2E2666B /* libPods-Bare.a */, - ); - name = Frameworks; - sourceTree = "<group>"; - }; - 20AA6A931D4A5D0C0062273A = { - isa = PBXGroup; - children = ( - 20AA6A9E1D4A5D0C0062273A /* Bare */, - 20AA6A9D1D4A5D0C0062273A /* Products */, - 959C411D2DDFE537E1860C73 /* Pods */, - 10E2F8C89368C139068A0B3E /* Frameworks */, - ); - sourceTree = "<group>"; - }; - 20AA6A9D1D4A5D0C0062273A /* Products */ = { - isa = PBXGroup; - children = ( - 20AA6A9C1D4A5D0C0062273A /* Bare.app */, - ); - name = Products; - sourceTree = "<group>"; - }; - 20AA6A9E1D4A5D0C0062273A /* Bare */ = { - isa = PBXGroup; - children = ( - 20AA6AA21D4A5D0C0062273A /* AppDelegate.h */, - 20AA6AA31D4A5D0C0062273A /* AppDelegate.m */, - 20AA6AA51D4A5D0C0062273A /* ViewController.h */, - 20AA6AA61D4A5D0C0062273A /* ViewController.m */, - 20AA6AA81D4A5D0C0062273A /* Main.storyboard */, - 20AA6AAB1D4A5D0C0062273A /* Assets.xcassets */, - 20AA6AAD1D4A5D0C0062273A /* LaunchScreen.storyboard */, - 20AA6AB01D4A5D0C0062273A /* Info.plist */, - 20AA6A9F1D4A5D0C0062273A /* Supporting Files */, - ); - path = Bare; - sourceTree = "<group>"; - }; - 20AA6A9F1D4A5D0C0062273A /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 20AA6AA01D4A5D0C0062273A /* main.m */, - ); - name = "Supporting Files"; - sourceTree = "<group>"; - }; - 959C411D2DDFE537E1860C73 /* Pods */ = { - isa = PBXGroup; - children = ( - 446F2F1AECCCB052B6006DEA /* Pods-Bare.debug.xcconfig */, - ED9C9E04E226DD8974E12F27 /* Pods-Bare.release.xcconfig */, - ); - name = Pods; - sourceTree = "<group>"; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 20AA6A9B1D4A5D0C0062273A /* Bare */ = { - isa = PBXNativeTarget; - buildConfigurationList = 20AA6AC91D4A5D0C0062273A /* Build configuration list for PBXNativeTarget "Bare" */; - buildPhases = ( - 7A75D07461562F0674F7524A /* [CP] Check Pods Manifest.lock */, - 20AA6A981D4A5D0C0062273A /* Sources */, - 20AA6A991D4A5D0C0062273A /* Frameworks */, - 20AA6A9A1D4A5D0C0062273A /* Resources */, - 914DEBFE9F34FA62FE43A1DC /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Bare; - productName = Bare; - productReference = 20AA6A9C1D4A5D0C0062273A /* Bare.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 20AA6A941D4A5D0C0062273A /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0730; - ORGANIZATIONNAME = google; - TargetAttributes = { - 20AA6A9B1D4A5D0C0062273A = { - CreatedOnToolsVersion = 7.3.1; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 20AA6A971D4A5D0C0062273A /* Build configuration list for PBXProject "Bare" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 20AA6A931D4A5D0C0062273A; - productRefGroup = 20AA6A9D1D4A5D0C0062273A /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 20AA6A9B1D4A5D0C0062273A /* Bare */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 20AA6A9A1D4A5D0C0062273A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 20AA6AAF1D4A5D0C0062273A /* LaunchScreen.storyboard in Resources */, - 20AA6AAC1D4A5D0C0062273A /* Assets.xcassets in Resources */, - 20AA6AAA1D4A5D0C0062273A /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 7A75D07461562F0674F7524A /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Bare-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 914DEBFE9F34FA62FE43A1DC /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Bare/Pods-Bare-resources.sh", - "${PODS_ROOT}/../../../components/ActivityIndicator/src/MaterialActivityIndicator.bundle", - "${PODS_ROOT}/../../../components/AppBar/src/MaterialAppBar.bundle", - "${PODS_ROOT}/../../../components/BottomNavigation/src/MaterialBottomNavigation.bundle", - "${PODS_ROOT}/../../../components/CollectionCells/src/MaterialCollectionCells.bundle", - "${PODS_ROOT}/../../../components/Collections/src/MaterialCollections.bundle", - "${PODS_ROOT}/../../../components/Dialogs/src/MaterialDialogs.bundle", - "${PODS_ROOT}/../../../components/FeatureHighlight/src/MaterialFeatureHighlight.bundle", - "${PODS_ROOT}/../../../components/PageControl/src/MaterialPageControl.bundle", - "${PODS_ROOT}/../../../components/Snackbar/src/MaterialSnackbar.bundle", - "${PODS_ROOT}/../../../components/Tabs/src/MaterialTabs.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_arrow_back.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_check.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_check_circle.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_chevron_right.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_color_lens.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_help_outline.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_info.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_more_horiz.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_radio_button_unchecked.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_reorder.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/MaterialComponents/MaterialIcons_ic_settings.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialActivityIndicator.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialAppBar.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialBottomNavigation.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCollectionCells.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCollections.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialDialogs.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialFeatureHighlight.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialPageControl.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialSnackbar.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialTabs.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_arrow_back.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_check.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_check_circle.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_chevron_right.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_color_lens.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_help_outline.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_info.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_more_horiz.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_radio_button_unchecked.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_reorder.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons_ic_settings.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Bare/Pods-Bare-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 20AA6A981D4A5D0C0062273A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 20AA6AA71D4A5D0C0062273A /* ViewController.m in Sources */, - 20AA6AA41D4A5D0C0062273A /* AppDelegate.m in Sources */, - 20AA6AA11D4A5D0C0062273A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 20AA6AA81D4A5D0C0062273A /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 20AA6AA91D4A5D0C0062273A /* Base */, - ); - name = Main.storyboard; - sourceTree = "<group>"; - }; - 20AA6AAD1D4A5D0C0062273A /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 20AA6AAE1D4A5D0C0062273A /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = "<group>"; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 20AA6AC71D4A5D0C0062273A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 20AA6AC81D4A5D0C0062273A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 20AA6ACA1D4A5D0C0062273A /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 446F2F1AECCCB052B6006DEA /* Pods-Bare.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = Bare/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.google.MaterialComponents.Bare; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 20AA6ACB1D4A5D0C0062273A /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = ED9C9E04E226DD8974E12F27 /* Pods-Bare.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = Bare/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.google.MaterialComponents.Bare; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 20AA6A971D4A5D0C0062273A /* Build configuration list for PBXProject "Bare" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 20AA6AC71D4A5D0C0062273A /* Debug */, - 20AA6AC81D4A5D0C0062273A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 20AA6AC91D4A5D0C0062273A /* Build configuration list for PBXNativeTarget "Bare" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 20AA6ACA1D4A5D0C0062273A /* Debug */, - 20AA6ACB1D4A5D0C0062273A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 20AA6A941D4A5D0C0062273A /* Project object */; -}
diff --git a/demos/Bare/Bare.xcodeproj/xcshareddata/xcschemes/Bare.xcscheme b/demos/Bare/Bare.xcodeproj/xcshareddata/xcschemes/Bare.xcscheme deleted file mode 100644 index 6d15e3a..0000000 --- a/demos/Bare/Bare.xcodeproj/xcshareddata/xcschemes/Bare.xcscheme +++ /dev/null
@@ -1,91 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Scheme - LastUpgradeVersion = "0730" - version = "1.3"> - <BuildAction - parallelizeBuildables = "YES" - buildImplicitDependencies = "YES"> - <BuildActionEntries> - <BuildActionEntry - buildForTesting = "YES" - buildForRunning = "YES" - buildForProfiling = "YES" - buildForArchiving = "YES" - buildForAnalyzing = "YES"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "20AA6A9B1D4A5D0C0062273A" - BuildableName = "Bare.app" - BlueprintName = "Bare" - ReferencedContainer = "container:Bare.xcodeproj"> - </BuildableReference> - </BuildActionEntry> - </BuildActionEntries> - </BuildAction> - <TestAction - buildConfiguration = "Debug" - selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" - selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - <Testables> - </Testables> - <MacroExpansion> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "20AA6A9B1D4A5D0C0062273A" - BuildableName = "Bare.app" - BlueprintName = "Bare" - ReferencedContainer = "container:Bare.xcodeproj"> - </BuildableReference> - </MacroExpansion> - <AdditionalOptions> - </AdditionalOptions> - </TestAction> - <LaunchAction - buildConfiguration = "Debug" - selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" - selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - launchStyle = "0" - useCustomWorkingDirectory = "NO" - ignoresPersistentStateOnLaunch = "NO" - debugDocumentVersioning = "YES" - debugServiceExtension = "internal" - allowLocationSimulation = "YES"> - <BuildableProductRunnable - runnableDebuggingMode = "0"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "20AA6A9B1D4A5D0C0062273A" - BuildableName = "Bare.app" - BlueprintName = "Bare" - ReferencedContainer = "container:Bare.xcodeproj"> - </BuildableReference> - </BuildableProductRunnable> - <AdditionalOptions> - </AdditionalOptions> - </LaunchAction> - <ProfileAction - buildConfiguration = "Release" - shouldUseLaunchSchemeArgsEnv = "YES" - savedToolIdentifier = "" - useCustomWorkingDirectory = "NO" - debugDocumentVersioning = "YES"> - <BuildableProductRunnable - runnableDebuggingMode = "0"> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "20AA6A9B1D4A5D0C0062273A" - BuildableName = "Bare.app" - BlueprintName = "Bare" - ReferencedContainer = "container:Bare.xcodeproj"> - </BuildableReference> - </BuildableProductRunnable> - </ProfileAction> - <AnalyzeAction - buildConfiguration = "Debug"> - </AnalyzeAction> - <ArchiveAction - buildConfiguration = "Release" - revealArchiveInOrganizer = "YES"> - </ArchiveAction> -</Scheme>
diff --git a/demos/Bare/Bare.xcworkspace/contents.xcworkspacedata b/demos/Bare/Bare.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index ae094d5..0000000 --- a/demos/Bare/Bare.xcworkspace/contents.xcworkspacedata +++ /dev/null
@@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Workspace - version = "1.0"> - <FileRef - location = "group:Bare.xcodeproj"> - </FileRef> - <FileRef - location = "group:Pods/Pods.xcodeproj"> - </FileRef> -</Workspace>
diff --git a/demos/Bare/Bare/AppDelegate.h b/demos/Bare/Bare/AppDelegate.h deleted file mode 100644 index 2edcc75..0000000 --- a/demos/Bare/Bare/AppDelegate.h +++ /dev/null
@@ -1,23 +0,0 @@ -/* - Copyright 2015-present the Material Components for iOS authors. 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 <UIKit/UIKit.h> - -@interface AppDelegate : UIResponder <UIApplicationDelegate> - -@property(strong, nonatomic) UIWindow *window; - -@end
diff --git a/demos/Bare/Bare/AppDelegate.m b/demos/Bare/Bare/AppDelegate.m deleted file mode 100644 index 2ab1d2b..0000000 --- a/demos/Bare/Bare/AppDelegate.m +++ /dev/null
@@ -1,32 +0,0 @@ -/* - Copyright 2015-present the Material Components for iOS authors. 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 "AppDelegate.h" - -@interface AppDelegate () - -@end - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // The purpose of this project is to measure the size of the Material Components for iOS library. - // There is nothing to see here. - return YES; -} - -@end
diff --git a/demos/Bare/Bare/Assets.xcassets/AppIcon.appiconset/Contents.json b/demos/Bare/Bare/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 1d060ed..0000000 --- a/demos/Bare/Bare/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null
@@ -1,93 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file
diff --git a/demos/Bare/Bare/Base.lproj/LaunchScreen.storyboard b/demos/Bare/Bare/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 5bc8b47..0000000 --- a/demos/Bare/Bare/Base.lproj/LaunchScreen.storyboard +++ /dev/null
@@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM"> - <dependencies> - <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> - </dependencies> - <scenes> - <!--View Controller--> - <scene sceneID="EHf-IW-A2E"> - <objects> - <viewController id="01J-lp-oVM" sceneMemberID="viewController"> - <layoutGuides> - <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/> - <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/> - </layoutGuides> - <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> - <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> - </view> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> - </objects> - <point key="canvasLocation" x="53" y="375"/> - </scene> - </scenes> -</document>
diff --git a/demos/Bare/Bare/Base.lproj/Main.storyboard b/demos/Bare/Bare/Base.lproj/Main.storyboard deleted file mode 100644 index 90eb181..0000000 --- a/demos/Bare/Bare/Base.lproj/Main.storyboard +++ /dev/null
@@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> - <dependencies> - <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> - </dependencies> - <scenes> - <!--View Controller--> - <scene sceneID="tne-QT-ifu"> - <objects> - <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"> - <layoutGuides> - <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> - <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> - </layoutGuides> - <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> - <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This project is used to measure the size of Material Components iOS. It has no functionality." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="5" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hkr-ZB-zkB"> - <rect key="frame" x="200" y="259" width="200" height="82"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> - <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> - <nil key="highlightedColor"/> - </label> - </subviews> - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> - <constraints> - <constraint firstItem="hkr-ZB-zkB" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="JXK-mu-VKd"/> - <constraint firstItem="hkr-ZB-zkB" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="jxS-31-Ogc"/> - </constraints> - </view> - </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> - </objects> - <point key="canvasLocation" x="305" y="415"/> - </scene> - </scenes> -</document>
diff --git a/demos/Bare/Bare/Info.plist b/demos/Bare/Bare/Info.plist deleted file mode 100644 index 40c6215..0000000 --- a/demos/Bare/Bare/Info.plist +++ /dev/null
@@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>en</string> - <key>CFBundleExecutable</key> - <string>$(EXECUTABLE_NAME)</string> - <key>CFBundleIdentifier</key> - <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleName</key> - <string>$(PRODUCT_NAME)</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleShortVersionString</key> - <string>1.0</string> - <key>CFBundleSignature</key> - <string>????</string> - <key>CFBundleVersion</key> - <string>1</string> - <key>LSRequiresIPhoneOS</key> - <true/> - <key>UILaunchStoryboardName</key> - <string>LaunchScreen</string> - <key>UIMainStoryboardFile</key> - <string>Main</string> - <key>UIRequiredDeviceCapabilities</key> - <array> - <string>armv7</string> - </array> - <key>UISupportedInterfaceOrientations</key> - <array> - <string>UIInterfaceOrientationPortrait</string> - <string>UIInterfaceOrientationLandscapeLeft</string> - <string>UIInterfaceOrientationLandscapeRight</string> - </array> - <key>UISupportedInterfaceOrientations~ipad</key> - <array> - <string>UIInterfaceOrientationPortrait</string> - <string>UIInterfaceOrientationPortraitUpsideDown</string> - <string>UIInterfaceOrientationLandscapeLeft</string> - <string>UIInterfaceOrientationLandscapeRight</string> - </array> -</dict> -</plist>
diff --git a/demos/Bare/Bare/ViewController.h b/demos/Bare/Bare/ViewController.h deleted file mode 100644 index d69a15e..0000000 --- a/demos/Bare/Bare/ViewController.h +++ /dev/null
@@ -1,21 +0,0 @@ -/* - Copyright 2015-present the Material Components for iOS authors. 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 <UIKit/UIKit.h> - -@interface ViewController : UIViewController - -@end
diff --git a/demos/Bare/Bare/ViewController.m b/demos/Bare/Bare/ViewController.m deleted file mode 100644 index 919a34a..0000000 --- a/demos/Bare/Bare/ViewController.m +++ /dev/null
@@ -1,21 +0,0 @@ -/* - Copyright 2015-present the Material Components for iOS authors. 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 "ViewController.h" - -@implementation ViewController - -@end
diff --git a/demos/Bare/Bare/main.m b/demos/Bare/Bare/main.m deleted file mode 100644 index 9f73fd3..0000000 --- a/demos/Bare/Bare/main.m +++ /dev/null
@@ -1,24 +0,0 @@ -/* - Copyright 2015-present the Material Components for iOS authors. 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 <UIKit/UIKit.h> -#import "AppDelegate.h" - -int main(int argc, char* argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -}
diff --git a/demos/Bare/Podfile b/demos/Bare/Podfile deleted file mode 100644 index ee35b06..0000000 --- a/demos/Bare/Podfile +++ /dev/null
@@ -1,6 +0,0 @@ -target 'Bare' do - platform :ios, '10.0' - project 'Bare.xcodeproj' - pod 'MaterialComponents', :path => '../../' -end -
diff --git a/demos/Bare/README.md b/demos/Bare/README.md deleted file mode 100644 index 5cd764e..0000000 --- a/demos/Bare/README.md +++ /dev/null
@@ -1,46 +0,0 @@ -# Bare - -An skeleton example App used to measure the size of Material Components for iOS. - -## Latest Measurement -| Bare App | Size | -|----------------------------------------------|----------| -| without Material Components iOS: | 2.7MB | -| with Material Components iOS: | 8.9MB | -|----------------------------------------------|----------| -| Delta by adding Material Components iOS: | 7.2MB | - -The Material Components iOS framework adds ~7.2MB to your project. -Measured on the 19.0.0 release. - -## Installation/Building - -Bare uses [CocoaPods](https://cocoapods.org/) for dependency -management. You will need CocoaPods as well as SSH access to -[material-components-ios](https://github.com/material-components/material-components-ios). -Needing SSH access is only temporary until MDC launches publicly. - -To install/build, cd into this directory and run `pod install`. -Then run `open Bare.xcworkspace`. Do **not** open `Bare.xcodeproj` -or the project will not build. - -## How we measured - -These are the instructions for how we took this measurement. - -### Create a base line -- Go to the `Podfile` and remove the `pod 'MaterialComponents', :path => '../../'` entry -- Measure the [size](#size-of-the-app-generated) of the App without Material Components. - -### Measure the increase with Material Components iOS -- Go to the `Podfile` and re-add the `pod 'MaterialComponents', :path => '../../'` entry -- Measure the [size](#size-of-the-app-generated) of the App with Material Components iOS. - - -### Size of the App generated -- Run `pod install` from the Bare root folder. -- Open the `Bare.xcworkspace`. -- Clean the build. -- Archive the Bare App. -- Find the `xcarchive` file and open it via `Show Contents of Package` -- Report back the size of `Products/Applications/Bar.app`
diff --git a/demos/README.md b/demos/README.md deleted file mode 100644 index 1fbe0f8..0000000 --- a/demos/README.md +++ /dev/null
@@ -1,32 +0,0 @@ -# Demo Apps for Material Components - -The following demo apps can be found in this directory: - -- [Bare](Bare/) - a skeleton example app used to measure the size of Material Components for iOS - -## Trying out Material Components - -Our [catalog](../catalog/) showcases Material Components. -You can use the `pod try` command from anywhere on your machine to try the components, even if you haven't checked out the repo yet: - -```bash -pod try MaterialComponents -``` - -In case you have already checked out the repo, run the following command: - -```bash -pod install --project-directory=catalog/ -``` - -- - - - -## Useful Links - -- [How To Use MDC-iOS](../docs/) -- [All Components](../components/) -- [Contributing](../contributing/) -- [MDC-iOS on Stack Overflow](https://www.stackoverflow.com/questions/tagged/material-components+ios) (external site) -- [Material.io](https://material.io) (external site) -- [Material Design Guidelines](https://material.io/guidelines) (external site) -
diff --git a/demos/supplemental/RemoteImageService/RemoteImageService.h b/demos/supplemental/RemoteImageService/RemoteImageService.h deleted file mode 100644 index aacf275..0000000 --- a/demos/supplemental/RemoteImageService/RemoteImageService.h +++ /dev/null
@@ -1,26 +0,0 @@ -/* - Copyright 2016-present the Material Components for iOS authors. 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 <UIKit/UIKit.h> - -@interface RemoteImageService : NSObject - -- (void)fetchImageAndThumbnailFromURL:(NSURL *)url - completion:(void (^)(UIImage *, UIImage *))completion; - -+ (instancetype)sharedService; - -@end
diff --git a/demos/supplemental/RemoteImageService/RemoteImageService.m b/demos/supplemental/RemoteImageService/RemoteImageService.m deleted file mode 100644 index f15f04e..0000000 --- a/demos/supplemental/RemoteImageService/RemoteImageService.m +++ /dev/null
@@ -1,115 +0,0 @@ -/* - Copyright 2016-present the Material Components for iOS authors. 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 "RemoteImageService.h" - -@interface RemoteImageService () - -@property(nonatomic) NSCache *dataCache; -@property(nonatomic) NSCache *imageCache; -@property(nonatomic) NSCache *thumbnailImageCache; -@property(nonatomic) NSCache *networkImageRequested; - -@end - -@implementation RemoteImageService - -- (instancetype)init { - self = [super init]; - if (self) { - _dataCache = [[NSCache alloc] init]; - _imageCache = [[NSCache alloc] init]; - _thumbnailImageCache = [[NSCache alloc] init]; - _networkImageRequested = [[NSCache alloc] init]; - } - return self; -} - -- (UIImage *)fetchImageFromURL:(NSURL *)url { - UIImage *image = [self.imageCache objectForKey:url]; - if (image) { - return image; - } else { - // Prevent the same image from being requested again if a network request is in progress. - if ([self.networkImageRequested objectForKey:url.absoluteString] != nil) { - return nil; - } else { - [self.networkImageRequested setObject:url forKey:url.absoluteString]; - } - } - - NSData *imageData = [[NSData alloc] initWithContentsOfURL:url]; - if (!imageData) { - return nil; - } - if (imageData) { - [self.dataCache setObject:imageData forKey:url]; - } else { - return nil; - } - image = [[UIImage alloc] initWithData:imageData]; - [self.imageCache setObject:image forKey:url]; - return image; -} - -- (UIImage *)fetchThumbnailImageFromURL:(NSURL *)url { - UIImage *thumbnailImage = [self.thumbnailImageCache objectForKey:url]; - if (thumbnailImage == nil) { - UIImage *image = [self fetchImageFromURL:url]; - if (!image) { - return nil; - } - thumbnailImage = [self createThumbnailWithImage:image]; - [self.thumbnailImageCache setObject:thumbnailImage forKey:url]; - } - return thumbnailImage; -} - -- (void)fetchImageAndThumbnailFromURL:(NSURL *)url - completion:(void (^)(UIImage *, UIImage *))completion { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - UIImage *image = [self fetchImageFromURL:url]; - UIImage *thumbnailImage = [self fetchThumbnailImageFromURL:url]; - completion(image, thumbnailImage); - }); -} - -- (UIImage *)createThumbnailWithImage:(UIImage *)image { - CGFloat scaleFactor = 0.2f; - CGSize scaledSize = CGSizeMake(image.size.width * scaleFactor, image.size.height * scaleFactor); - UIImage *thumbnailImage = [RemoteImageService imageWithImage:image scaledToSize:scaledSize]; - return thumbnailImage; -} - -+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize { - UIGraphicsBeginImageContextWithOptions(newSize, NO, 0); - [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; - UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return newImage; -} - -+ (instancetype)sharedService { - static RemoteImageService *instance = nil; - static dispatch_once_t onceToken = 0; - dispatch_once(&onceToken, ^{ - instance = [[RemoteImageService alloc] init]; - }); - - return instance; -} - -@end
diff --git a/demos/supplemental/RemoteImageServiceForMDCDemos.podspec b/demos/supplemental/RemoteImageServiceForMDCDemos.podspec deleted file mode 100644 index b494171..0000000 --- a/demos/supplemental/RemoteImageServiceForMDCDemos.podspec +++ /dev/null
@@ -1,12 +0,0 @@ -Pod::Spec.new do |s| - s.name = "RemoteImageServiceForMDCDemos" - s.version = "124.1.1" - s.summary = "A helper image class for the MDC demos." - s.description = "This spec is made for use in the MDC demos. It gets images via url." - s.homepage = "https://github.com/material-components/material-components-ios" - s.license = "Apache 2.0" - s.authors = { 'Apple platform engineering at Google' => 'appleplatforms@google.com' } - s.source = { :git => "https://github.com/material-components/material-components-ios.git", :tag => "v#{s.version}" } - s.source_files = "RemoteImageService/*.{h,m}" - s.public_header_files = "RemoteImageService/*.h" -end
diff --git a/docs/supporting-shapes/README.md b/docs/supporting-shapes/README.md index 7a08145..7fd3b58 100644 --- a/docs/supporting-shapes/README.md +++ b/docs/supporting-shapes/README.md
@@ -131,7 +131,7 @@ <img src="assets/diamondfab.gif" alt="Diamond FAB."> <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift let floatingButton = MDCFloatingButton() floatingButton.setImage(plusImage for:.normal) @@ -143,7 +143,7 @@ self.view.addSubview(floatingButton) ``` -##### Objective-C +#### Objective-C ```objc self.floatingButton = [[MDCFloatingButton alloc] init]; [self.floatingButton setImage:plusImage forState:UIControlStateNormal]; @@ -162,7 +162,7 @@ <img src="assets/cutcornersbutton.gif" alt="Cut Corners Button."> <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift let containedButton = MDCButton() containedButton.setTitle("Add To Cart" for:.normal) @@ -176,7 +176,7 @@ self.view.addSubview(containedButton) ``` -##### Objective-C +#### Objective-C ```objc MDCButton *containedButton = [[MDCButton alloc] init]; [containedButton setTitle:@"Add To Cart" forState:UIControlStateNormal]; @@ -197,7 +197,7 @@ <img src="assets/cardcellcutcorner.gif" alt="Card Cell Cut Corner."> <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { @@ -209,7 +209,7 @@ return cell ``` -##### Objective-C +#### Objective-C ```objc - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { @@ -230,7 +230,7 @@ <img src="assets/cardwithdiffcorners.gif" alt="Card With Different Corners."> <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift let card = MDCCard() let shapeGenerator = MDCRectangleShapeGenerator() @@ -244,7 +244,7 @@ card.shapeGenerator = shapeGenerator ``` -##### Objective-C +#### Objective-C ```objc MDCCard *card = [[MDCCard alloc] init]; MDCRectangleShapeGenerator *shapeGenerator =
diff --git a/docs/theming.md b/docs/theming.md index b656a91..90343a1 100644 --- a/docs/theming.md +++ b/docs/theming.md
@@ -255,7 +255,7 @@ Replace any Themer import with the component's Theming import: <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift // Old @@ -265,7 +265,7 @@ import MaterialComponents.MaterialTextFields_Theming ``` -##### Objective-C +#### Objective-C ```objc // Old @@ -282,7 +282,7 @@ equivalent Theming extension is described in the Themer's header documentation. <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift // Old @@ -294,7 +294,7 @@ textField.applyTheme(withScheme: scheme) ``` -##### Objective-C +#### Objective-C ```objc // Old @@ -313,7 +313,7 @@ then you'll likely only need to make these customizations once. <!--<div class="material-code-render" markdown="1">--> -##### Swift +#### Swift ```swift // Old @@ -325,7 +325,7 @@ scheme.colorScheme.primaryColor = .red ``` -##### Objective-C +#### Objective-C ```objc // Old