diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 46753da..0000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,17 +0,0 @@ -- [ ] I have verified there are no duplicate active or recent bugs, questions, or requests - -###### Include the following: - - SCLAlertView version: `1.0.3` - - Device OS version: `6.0` - - Device Name: `iPhone 6` - -###### Reproduction Steps - 1. - 2. - 3. - -###### Expected Result - -###### Actual Result - -### Tell us what could be improved: diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..83e0d86 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..066b2d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..cb82aa4 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,18 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 30 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - enhancement + - bug + - help wanted +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml new file mode 100755 index 0000000..dcc21c6 --- /dev/null +++ b/.github/workflows/Build.yml @@ -0,0 +1,36 @@ +name: Building +on: [push, pull_request] + +jobs: + build: + name: Building SCLAlertView + runs-on: macos-15 + strategy: + matrix: + scheme: [ + SCLAlertView + ] + destination: [ + 'platform=iOS Simulator,name=iPhone 16,OS=26.1' + ] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Xcode version + uses: maxim-lobanov/setup-xcode@v1.6.0 + with: + xcode-version: 26.1 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3.0 + bundler-cache: true + + - name: Building ${{ matrix.scheme }} on ${{ matrix.destination }} + run: | + set -o pipefail && xcodebuild -project SCLAlertView.xcodeproj \ + -scheme ${{ matrix.scheme }} \ + -destination '${{ matrix.destination }}' \ + clean build | xcbeautify --renderer github-actions diff --git a/.gitignore b/.gitignore index fd94552..eda364b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,7 @@ DerivedData *.ipa *.xcuserstate -# CocoaPods +# SPM # -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control -# -# Pods/ +.build/ +Derived/ diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 2bf1c1c..0000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.3.1 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9158c8b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -# reference: http://www.objc.io/issue-6/travis-ci.html - -language: objective-c -osx_image: xcode8.3 - -script: -- xcodebuild -project SCLAlertView.xcodeproj -target SCLAlertView -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6792310..9f668f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,98 @@ -# Change Log +# Changelog -## [Unreleased](https://github.com/dogo/SCLAlertView/tree/HEAD) +## [1.3.0](https://github.com/dogo/SCLAlertView/tree/1.3.0) (2023-12-20) -[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.3...HEAD) +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.2.0...1.3.0) **Closed issues:** +- Android system can use it even better [\#307](https://github.com/dogo/SCLAlertView/issues/307) +- showCustom 的时候如何自定义 closeButton样式 [\#302](https://github.com/dogo/SCLAlertView/issues/302) +- Cannot find ChangesLog for version 1.2.0 [\#299](https://github.com/dogo/SCLAlertView/issues/299) +- Is this an SCLAlertView bug, or an Apple bug? [\#296](https://github.com/dogo/SCLAlertView/issues/296) +- SCLAlertView \*alert = \[\[SCLAlertView alloc\] initWithNewWindowWidth:300.0f\]; self.username = @"zaxo"; self.password = @"pass"; UITextField \*usernameTextField = \[alert addTextField:@"username"\]; UITextField \*passwordTextField = \[alert addTextField:@"password"\]; passwordTextField.secureTextEntry = YES; \[alert addButton:@"Login" actionBlock: ^\(void\){ BOOL isUsersEqual = \[self.username isEqualToString:\[self.usernameTextField text\]\]; BOOL isPasswordsEqual = \[self.password isEqualToString:\[self.passwordTextField text\]\]; if\(isUsersEqual && isPasswordsEqual\){ NSLog\(@"Successful"\); } else { NSLog\(@"frailer"\); } @@@@@@@@ Why I can't compile it I even have set the @Property \(nonatomic, strong\) NSString \*username; in SCLALertView.m but I still errors do im doing anthing please can you help Tweak.xm:350:1: error: use of undeclared identifier 'self' self.username = @"zaxo"; [\#293](https://github.com/dogo/SCLAlertView/issues/293) + +**Merged pull requests:** + +- Add initWithWidth method for setting the width of the object. [\#310](https://github.com/dogo/SCLAlertView/pull/310) ([FernandoReynoso](https://github.com/FernandoReynoso)) +- Bump activesupport from 6.1.5 to 6.1.7.3 [\#308](https://github.com/dogo/SCLAlertView/pull/308) ([dependabot[bot]](https://github.com/apps/dependabot)) +- default value for a textfield [\#295](https://github.com/dogo/SCLAlertView/pull/295) ([syto203](https://github.com/syto203)) + +## [1.2.0](https://github.com/dogo/SCLAlertView/tree/1.2.0) (2020-10-31) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.6...1.2.0) + +**Closed issues:** + +- alertView with textfield moves up twice\(too much\) when textfield become first responder and the keyboard shows [\#291](https://github.com/dogo/SCLAlertView/issues/291) +- 设置富文本后不居中显示了 变成了居左。 [\#288](https://github.com/dogo/SCLAlertView/issues/288) +- Good day, as you can implement the verification key which is located on the website .txt document? Roughly speaking to make check on a key if the key is correct, then there is a start. [\#286](https://github.com/dogo/SCLAlertView/issues/286) +- How to hidden top image with OC? [\#285](https://github.com/dogo/SCLAlertView/issues/285) + +**Merged pull requests:** + +- Fix: break a strong reference cycle [\#290](https://github.com/dogo/SCLAlertView/pull/290) ([kingste](https://github.com/kingste)) +- Merge [\#279](https://github.com/dogo/SCLAlertView/pull/279) ([dogo](https://github.com/dogo)) +- Add Stale config [\#275](https://github.com/dogo/SCLAlertView/pull/275) ([dogo](https://github.com/dogo)) + +## [1.1.6](https://github.com/dogo/SCLAlertView/tree/1.1.6) (2018-10-14) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.5...1.1.6) + +**Implemented enhancements:** + +- ButtonTimer: Enable button once timer elapsed [\#181](https://github.com/dogo/SCLAlertView/issues/181) + +**Fixed bugs:** + +- UIStatusBarStyle always appears as 'UIStatusBarStyleDefault' [\#274](https://github.com/dogo/SCLAlertView/issues/274) +- Alert view height problem when using it with long text in body [\#127](https://github.com/dogo/SCLAlertView/issues/127) + +**Closed issues:** + +- handleNavigationTransition Bug [\#276](https://github.com/dogo/SCLAlertView/issues/276) +- Could you release fixed version? [\#273](https://github.com/dogo/SCLAlertView/issues/273) +- Accessibility: implement - \(BOOL\)accessibilityPerformEscape [\#271](https://github.com/dogo/SCLAlertView/issues/271) +- How to solve the problem of overlapping multiple calls in a controller?(如何解决在一个控制器中,连续多次调用,会出现重叠的情况?) [\#267](https://github.com/dogo/SCLAlertView/issues/267) +- TextView height problem when text entered with the long body \(it need to expend it's height \) [\#258](https://github.com/dogo/SCLAlertView/issues/258) +- i need to add on the preloaded text in the text field before textfield Alert pop up [\#254](https://github.com/dogo/SCLAlertView/issues/254) +- Problem in increasing height of TextField & customize the Alert view colour & image & button [\#253](https://github.com/dogo/SCLAlertView/issues/253) +- Custom TextField not adding Keyboard Observers [\#250](https://github.com/dogo/SCLAlertView/issues/250) +- Portrait or Landscape fixed [\#201](https://github.com/dogo/SCLAlertView/issues/201) +- \[Bug\] when changing keyboard... [\#200](https://github.com/dogo/SCLAlertView/issues/200) +- If new alert is displayed before 1st waiting alert is closed by duration, then 1st alert will never automatically close [\#178](https://github.com/dogo/SCLAlertView/issues/178) +- Add support to show only one alert view at the same time. [\#141](https://github.com/dogo/SCLAlertView/issues/141) +- UITextField Return/Done Action \(UIControlEventEditingDidEndOnExit\) [\#123](https://github.com/dogo/SCLAlertView/issues/123) + +## [1.1.5](https://github.com/dogo/SCLAlertView/tree/1.1.5) (2018-06-22) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.4...1.1.5) + +**Merged pull requests:** + +- core: base builder with fluent has been added. [\#272](https://github.com/dogo/SCLAlertView/pull/272) ([lolgear](https://github.com/lolgear)) + +## [1.1.4](https://github.com/dogo/SCLAlertView/tree/1.1.4) (2018-06-19) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.3...1.1.4) + +**Closed issues:** + +- Eliminate warnings [\#270](https://github.com/dogo/SCLAlertView/issues/270) +- How to add in multiple subtitle in an alert view? [\#266](https://github.com/dogo/SCLAlertView/issues/266) - SCLAlertViewHideAnimation wrong animations [\#262](https://github.com/dogo/SCLAlertView/issues/262) +- Title truncated [\#259](https://github.com/dogo/SCLAlertView/issues/259) - Use the builder pattern to build a SCLAlertView? [\#256](https://github.com/dogo/SCLAlertView/issues/256) - Carthage Support [\#255](https://github.com/dogo/SCLAlertView/issues/255) +**Merged pull requests:** + +- Fluent style project cleanup. [\#269](https://github.com/dogo/SCLAlertView/pull/269) ([lolgear](https://github.com/lolgear)) +- Create CONTRIBUTING.md [\#265](https://github.com/dogo/SCLAlertView/pull/265) ([dogo](https://github.com/dogo)) +- Create CODE\_OF\_CONDUCT.md [\#264](https://github.com/dogo/SCLAlertView/pull/264) ([dogo](https://github.com/dogo)) + ## [1.1.3](https://github.com/dogo/SCLAlertView/tree/1.1.3) (2018-01-17) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.2...1.1.3) **Fixed bugs:** @@ -35,6 +117,7 @@ - clerical error [\#249](https://github.com/dogo/SCLAlertView/pull/249) ([amisare](https://github.com/amisare)) ## [1.1.2](https://github.com/dogo/SCLAlertView/tree/1.1.2) (2017-04-11) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.1...1.1.2) **Closed issues:** @@ -48,6 +131,7 @@ - Command failed due to signal: Segmentation fault: 11 swift 3 [\#221](https://github.com/dogo/SCLAlertView/issues/221) ## [1.1.1](https://github.com/dogo/SCLAlertView/tree/1.1.1) (2017-02-16) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.0...1.1.1) **Closed issues:** @@ -64,6 +148,7 @@ - Dismiss Animation Completion Block [\#239](https://github.com/dogo/SCLAlertView/pull/239) ([hydr93](https://github.com/hydr93)) ## [1.1.0](https://github.com/dogo/SCLAlertView/tree/1.1.0) (2016-12-07) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.6...1.1.0) **Closed issues:** @@ -75,11 +160,12 @@ **Merged pull requests:** -- Add button custom font support when use buttonConfig block [\#232](https://github.com/dogo/SCLAlertView/pull/232) ([marcoslacerda](https://github.com/marcoslacerda)) +- Add button custom font support when use buttonConfig block [\#232](https://github.com/dogo/SCLAlertView/pull/232) ([maclacerda](https://github.com/maclacerda)) - fix the bug: dismiss SCLAlertViewHideAnimationSimplyDisappear hideAni… [\#230](https://github.com/dogo/SCLAlertView/pull/230) ([JoakimLiu](https://github.com/JoakimLiu)) - Change auto-capitalisation to sentence only [\#229](https://github.com/dogo/SCLAlertView/pull/229) ([idrougge](https://github.com/idrougge)) ## [1.0.6](https://github.com/dogo/SCLAlertView/tree/1.0.6) (2016-10-27) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.5...1.0.6) **Fixed bugs:** @@ -104,6 +190,7 @@ - Changed constants names to avoid name collision [\#224](https://github.com/dogo/SCLAlertView/pull/224) ([damarte](https://github.com/damarte)) ## [1.0.5](https://github.com/dogo/SCLAlertView/tree/1.0.5) (2016-09-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.4...1.0.5) **Closed issues:** @@ -115,11 +202,12 @@ **Merged pull requests:** -- Add umbrella header to exclude warnings during framework building [\#220](https://github.com/dogo/SCLAlertView/pull/220) ([alokard](https://github.com/alokard)) -- Add Carthage support [\#210](https://github.com/dogo/SCLAlertView/pull/210) ([alokard](https://github.com/alokard)) +- Add umbrella header to exclude warnings during framework building [\#220](https://github.com/dogo/SCLAlertView/pull/220) ([goncharik](https://github.com/goncharik)) +- Add Carthage support [\#210](https://github.com/dogo/SCLAlertView/pull/210) ([goncharik](https://github.com/goncharik)) - docs: nativescript integration mention [\#209](https://github.com/dogo/SCLAlertView/pull/209) ([NathanWalker](https://github.com/NathanWalker)) ## [1.0.4](https://github.com/dogo/SCLAlertView/tree/1.0.4) (2016-06-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.3...1.0.4) **Closed issues:** @@ -129,6 +217,7 @@ - ShowWaiting timer error [\#202](https://github.com/dogo/SCLAlertView/issues/202) ## [1.0.3](https://github.com/dogo/SCLAlertView/tree/1.0.3) (2016-05-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.2...1.0.3) **Closed issues:** @@ -143,12 +232,15 @@ - Adds show/hide AnimationTypes 'SimplyAppear' and 'SimplyDisappear' i.e., 'None' [\#198](https://github.com/dogo/SCLAlertView/pull/198) ([AmitaiB](https://github.com/AmitaiB)) ## [1.0.2](https://github.com/dogo/SCLAlertView/tree/1.0.2) (2016-03-16) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.1...1.0.2) ## [1.0.1](https://github.com/dogo/SCLAlertView/tree/1.0.1) (2016-03-08) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.0...1.0.1) ## [1.0.0](https://github.com/dogo/SCLAlertView/tree/1.0.0) (2016-03-07) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.3...1.0.0) **Closed issues:** @@ -166,6 +258,7 @@ - Fluent style support [\#189](https://github.com/dogo/SCLAlertView/pull/189) ([lolgear](https://github.com/lolgear)) ## [0.9.3](https://github.com/dogo/SCLAlertView/tree/0.9.3) (2016-03-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.2...0.9.3) **Implemented enhancements:** @@ -173,6 +266,7 @@ - Add bounce animation to all slides [\#116](https://github.com/dogo/SCLAlertView/issues/116) ## [0.9.2](https://github.com/dogo/SCLAlertView/tree/0.9.2) (2016-03-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.1...0.9.2) **Closed issues:** @@ -180,9 +274,11 @@ - Vertical spacing broken on 0.9.0 [\#183](https://github.com/dogo/SCLAlertView/issues/183) ## [0.9.1](https://github.com/dogo/SCLAlertView/tree/0.9.1) (2016-02-15) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.0...0.9.1) ## [0.9.0](https://github.com/dogo/SCLAlertView/tree/0.9.0) (2016-02-10) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.8.2...0.9.0) **Implemented enhancements:** @@ -204,6 +300,7 @@ - Change play sound class [\#171](https://github.com/dogo/SCLAlertView/pull/171) ([Liqiankun](https://github.com/Liqiankun)) ## [0.8.2](https://github.com/dogo/SCLAlertView/tree/0.8.2) (2016-01-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.8.1...0.8.2) **Closed issues:** @@ -211,6 +308,7 @@ - Memory leak using new window way to display [\#142](https://github.com/dogo/SCLAlertView/issues/142) ## [0.8.1](https://github.com/dogo/SCLAlertView/tree/0.8.1) (2016-01-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.8.0...0.8.1) **Fixed bugs:** @@ -224,6 +322,7 @@ - Multitasking Split Screen Bug [\#158](https://github.com/dogo/SCLAlertView/issues/158) ## [0.8.0](https://github.com/dogo/SCLAlertView/tree/0.8.0) (2015-12-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.9...0.8.0) **Fixed bugs:** @@ -247,9 +346,9 @@ - Develop [\#163](https://github.com/dogo/SCLAlertView/pull/163) ([jusefjames](https://github.com/jusefjames)) - Prevent viewText scrollable [\#154](https://github.com/dogo/SCLAlertView/pull/154) ([AzulesM](https://github.com/AzulesM)) - Fixing centering problem when used in iPad split view [\#153](https://github.com/dogo/SCLAlertView/pull/153) ([abbasmousavi](https://github.com/abbasmousavi)) -- To get the correct subtitle height [\#152](https://github.com/dogo/SCLAlertView/pull/152) ([AzulesM](https://github.com/AzulesM)) ## [0.7.9](https://github.com/dogo/SCLAlertView/tree/0.7.9) (2015-10-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.7...0.7.9) **Fixed bugs:** @@ -267,6 +366,7 @@ - Namespace SCLActionTypes to avoid conflicts [\#144](https://github.com/dogo/SCLAlertView/pull/144) ([mbelkin](https://github.com/mbelkin)) ## [0.7.7](https://github.com/dogo/SCLAlertView/tree/0.7.7) (2015-09-17) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.6...0.7.7) **Closed issues:** @@ -276,9 +376,11 @@ - Modules enabled but still getting disabled error [\#136](https://github.com/dogo/SCLAlertView/issues/136) ## [0.7.6](https://github.com/dogo/SCLAlertView/tree/0.7.6) (2015-09-15) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.5...0.7.6) ## [0.7.5](https://github.com/dogo/SCLAlertView/tree/0.7.5) (2015-09-02) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.4...0.7.5) **Closed issues:** @@ -291,6 +393,7 @@ - Dynamically set button height to allow for multiple lines of text. [\#139](https://github.com/dogo/SCLAlertView/pull/139) ([yatryan](https://github.com/yatryan)) ## [0.7.4](https://github.com/dogo/SCLAlertView/tree/0.7.4) (2015-07-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.3...0.7.4) **Closed issues:** @@ -313,6 +416,7 @@ - fix bug [\#134](https://github.com/dogo/SCLAlertView/pull/134) ([HuylensHu](https://github.com/HuylensHu)) ## [0.7.3](https://github.com/dogo/SCLAlertView/tree/0.7.3) (2015-06-10) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.2...0.7.3) **Closed issues:** @@ -320,6 +424,7 @@ - check TextField.text is empty. [\#122](https://github.com/dogo/SCLAlertView/issues/122) ## [0.7.2](https://github.com/dogo/SCLAlertView/tree/0.7.2) (2015-05-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.1...0.7.2) **Fixed bugs:** @@ -339,6 +444,7 @@ - If defaultBackgroundColor is preconfigured for button its not changed to... [\#109](https://github.com/dogo/SCLAlertView/pull/109) ([alex1704](https://github.com/alex1704)) ## [0.7.1](https://github.com/dogo/SCLAlertView/tree/0.7.1) (2015-05-04) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.0...0.7.1) **Fixed bugs:** @@ -360,6 +466,7 @@ - ignore depreceted inside SCLAlertView [\#103](https://github.com/dogo/SCLAlertView/pull/103) ([jcavar](https://github.com/jcavar)) ## [0.7.0](https://github.com/dogo/SCLAlertView/tree/0.7.0) (2015-04-01) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.6.1...0.7.0) **Fixed bugs:** @@ -377,25 +484,26 @@ - fix screen stutter glitch with blur background [\#96](https://github.com/dogo/SCLAlertView/pull/96) ([felix-dumit](https://github.com/felix-dumit)) - Fixes a bug where you could not set Font attributes on the attributed st... [\#88](https://github.com/dogo/SCLAlertView/pull/88) ([n1mda](https://github.com/n1mda)) +- Automatically add a borderWidth to the button if borderColor is defined [\#85](https://github.com/dogo/SCLAlertView/pull/85) ([jeremygrenier](https://github.com/jeremygrenier)) ## [0.6.1](https://github.com/dogo/SCLAlertView/tree/0.6.1) (2015-03-23) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.6.0...0.6.1) ## [0.6.0](https://github.com/dogo/SCLAlertView/tree/0.6.0) (2015-03-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.9...0.6.0) **Closed issues:** - new alert flick [\#83](https://github.com/dogo/SCLAlertView/issues/83) -**Merged pull requests:** - -- Automatically add a borderWidth to the button if borderColor is defined [\#85](https://github.com/dogo/SCLAlertView/pull/85) ([jeremygrenier](https://github.com/jeremygrenier)) - ## [0.5.9](https://github.com/dogo/SCLAlertView/tree/0.5.9) (2015-03-18) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.8...0.5.9) ## [0.5.8](https://github.com/dogo/SCLAlertView/tree/0.5.8) (2015-03-17) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.7...0.5.8) **Implemented enhancements:** @@ -403,6 +511,7 @@ - Custom button height feature request [\#71](https://github.com/dogo/SCLAlertView/issues/71) ## [0.5.7](https://github.com/dogo/SCLAlertView/tree/0.5.7) (2015-03-16) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.6...0.5.7) **Closed issues:** @@ -412,6 +521,7 @@ - BOOL visibility of alert needed [\#73](https://github.com/dogo/SCLAlertView/issues/73) ## [0.5.6](https://github.com/dogo/SCLAlertView/tree/0.5.6) (2015-03-05) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.5...0.5.6) **Fixed bugs:** @@ -419,6 +529,7 @@ - Latest Version Fails To Build [\#74](https://github.com/dogo/SCLAlertView/issues/74) ## [0.5.5](https://github.com/dogo/SCLAlertView/tree/0.5.5) (2015-02-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.4...0.5.5) **Closed issues:** @@ -430,6 +541,7 @@ - Minor icon and button customization fixes [\#70](https://github.com/dogo/SCLAlertView/pull/70) ([wzs](https://github.com/wzs)) ## [0.5.4](https://github.com/dogo/SCLAlertView/tree/0.5.4) (2015-02-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.3...0.5.4) **Implemented enhancements:** @@ -442,11 +554,10 @@ **Fixed bugs:** -- AlertView does not disable Interactive Pop Gesture [\#66](https://github.com/dogo/SCLAlertView/issues/66) -- Blur background is wrong when shown from "UIModalPresentationFormSheet" [\#65](https://github.com/dogo/SCLAlertView/issues/65) - The white background view is too long [\#53](https://github.com/dogo/SCLAlertView/issues/53) ## [0.5.3](https://github.com/dogo/SCLAlertView/tree/0.5.3) (2015-02-02) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.2...0.5.3) **Fixed bugs:** @@ -458,6 +569,7 @@ - textarea in alert [\#61](https://github.com/dogo/SCLAlertView/issues/61) ## [0.5.2](https://github.com/dogo/SCLAlertView/tree/0.5.2) (2015-01-27) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.1...0.5.2) **Implemented enhancements:** @@ -469,6 +581,7 @@ - ability to only show one alert [\#56](https://github.com/dogo/SCLAlertView/issues/56) ## [0.5.1](https://github.com/dogo/SCLAlertView/tree/0.5.1) (2015-01-26) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.0...0.5.1) **Implemented enhancements:** @@ -485,6 +598,7 @@ - Rotating with keyboard [\#36](https://github.com/dogo/SCLAlertView/issues/36) ## [0.5.0](https://github.com/dogo/SCLAlertView/tree/0.5.0) (2015-01-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.3...0.5.0) **Fixed bugs:** @@ -492,6 +606,7 @@ - Display in formsheet [\#50](https://github.com/dogo/SCLAlertView/issues/50) ## [0.4.3](https://github.com/dogo/SCLAlertView/tree/0.4.3) (2015-01-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.2...0.4.3) **Closed issues:** @@ -499,6 +614,7 @@ - Change Title Size [\#42](https://github.com/dogo/SCLAlertView/issues/42) ## [0.4.2](https://github.com/dogo/SCLAlertView/tree/0.4.2) (2015-01-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.1...0.4.2) **Closed issues:** @@ -507,6 +623,7 @@ - does not work with UIPIckview [\#26](https://github.com/dogo/SCLAlertView/issues/26) ## [0.4.1](https://github.com/dogo/SCLAlertView/tree/0.4.1) (2015-01-19) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.0...0.4.1) **Closed issues:** @@ -515,6 +632,7 @@ - Landscape not working on iPad [\#48](https://github.com/dogo/SCLAlertView/issues/48) ## [0.4.0](https://github.com/dogo/SCLAlertView/tree/0.4.0) (2015-01-19) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.9...0.4.0) **Fixed bugs:** @@ -531,9 +649,11 @@ - fix \#44 [\#47](https://github.com/dogo/SCLAlertView/pull/47) ([portwatcher](https://github.com/portwatcher)) ## [0.3.9](https://github.com/dogo/SCLAlertView/tree/0.3.9) (2015-01-15) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.8...0.3.9) ## [0.3.8](https://github.com/dogo/SCLAlertView/tree/0.3.8) (2015-01-12) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.7...0.3.8) **Implemented enhancements:** @@ -545,6 +665,7 @@ - alertview position issue [\#39](https://github.com/dogo/SCLAlertView/issues/39) ## [0.3.7](https://github.com/dogo/SCLAlertView/tree/0.3.7) (2014-12-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.6...0.3.7) **Closed issues:** @@ -558,6 +679,7 @@ - Subtitle Height Setting [\#34](https://github.com/dogo/SCLAlertView/pull/34) ([ancloid](https://github.com/ancloid)) ## [0.3.6](https://github.com/dogo/SCLAlertView/tree/0.3.6) (2014-12-09) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.5...0.3.6) **Closed issues:** @@ -571,6 +693,7 @@ - modified podspec file to support iOS6 [\#33](https://github.com/dogo/SCLAlertView/pull/33) ([shannonchou](https://github.com/shannonchou)) ## [0.3.5](https://github.com/dogo/SCLAlertView/tree/0.3.5) (2014-11-28) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.4...0.3.5) **Implemented enhancements:** @@ -583,6 +706,7 @@ - EXC\_BAD\_ACCESS \(code=1\) [\#28](https://github.com/dogo/SCLAlertView/issues/28) ## [0.3.4](https://github.com/dogo/SCLAlertView/tree/0.3.4) (2014-11-14) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.3...0.3.4) **Closed issues:** @@ -590,9 +714,11 @@ - Any way to show this from a UIView? [\#11](https://github.com/dogo/SCLAlertView/issues/11) ## [0.3.3](https://github.com/dogo/SCLAlertView/tree/0.3.3) (2014-11-11) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.2...0.3.3) ## [0.3.2](https://github.com/dogo/SCLAlertView/tree/0.3.2) (2014-11-05) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.1...0.3.2) **Fixed bugs:** @@ -604,9 +730,11 @@ - Any of the showAnimationType not working [\#22](https://github.com/dogo/SCLAlertView/issues/22) ## [0.3.1](https://github.com/dogo/SCLAlertView/tree/0.3.1) (2014-11-04) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.0...0.3.1) ## [0.3.0](https://github.com/dogo/SCLAlertView/tree/0.3.0) (2014-11-04) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.6...0.3.0) **Implemented enhancements:** @@ -630,18 +758,23 @@ - fix showAnimation bug [\#19](https://github.com/dogo/SCLAlertView/pull/19) ([sanshanchuns](https://github.com/sanshanchuns)) ## [0.2.6](https://github.com/dogo/SCLAlertView/tree/0.2.6) (2014-10-23) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.5...0.2.6) ## [0.2.5](https://github.com/dogo/SCLAlertView/tree/0.2.5) (2014-10-23) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.4...0.2.5) ## [0.2.4](https://github.com/dogo/SCLAlertView/tree/0.2.4) (2014-10-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.3...0.2.4) ## [0.2.3](https://github.com/dogo/SCLAlertView/tree/0.2.3) (2014-10-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.2...0.2.3) ## [0.2.2](https://github.com/dogo/SCLAlertView/tree/0.2.2) (2014-10-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.1...0.2.2) **Implemented enhancements:** @@ -649,6 +782,7 @@ - is possible button show touch down or touch up display? [\#10](https://github.com/dogo/SCLAlertView/issues/10) ## [0.2.1](https://github.com/dogo/SCLAlertView/tree/0.2.1) (2014-10-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.0...0.2.1) **Closed issues:** @@ -661,6 +795,7 @@ - Add validation block [\#9](https://github.com/dogo/SCLAlertView/pull/9) ([mamaral](https://github.com/mamaral)) ## [0.2.0](https://github.com/dogo/SCLAlertView/tree/0.2.0) (2014-10-18) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.1.2...0.2.0) **Implemented enhancements:** @@ -674,6 +809,7 @@ - Custom icon and color [\#6](https://github.com/dogo/SCLAlertView/pull/6) ([mamaral](https://github.com/mamaral)) ## [0.1.2](https://github.com/dogo/SCLAlertView/tree/0.1.2) (2014-10-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.1.1...0.1.2) **Closed issues:** @@ -682,18 +818,25 @@ - Issues with a side menu controller [\#1](https://github.com/dogo/SCLAlertView/issues/1) ## [0.1.1](https://github.com/dogo/SCLAlertView/tree/0.1.1) (2014-10-09) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.1.0...0.1.1) ## [0.1.0](https://github.com/dogo/SCLAlertView/tree/0.1.0) (2014-10-08) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.0.3...0.1.0) ## [0.0.3](https://github.com/dogo/SCLAlertView/tree/0.0.3) (2014-10-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.0.2...0.0.3) ## [0.0.2](https://github.com/dogo/SCLAlertView/tree/0.0.2) (2014-09-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.0.1...0.0.2) ## [0.0.1](https://github.com/dogo/SCLAlertView/tree/0.0.1) (2014-09-29) +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/49477fbc62f611ec0dd04590afa3d29972b60d22...0.0.1) + + -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..f464f57 --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true +source "https://rubygems.org" + +ruby "3.3.0" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +gem "cocoapods" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..71db6a9 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,134 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.8) + activesupport (7.2.3.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1, < 6) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.2) + claide (1.1.0) + cocoapods (1.16.2) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.16.2) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.27.0, < 2.0) + cocoapods-core (1.16.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + drb (2.2.3) + escape (0.0.4) + ethon (0.18.0) + ffi (>= 1.15.0) + logger + ffi (1.17.4) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86-linux-gnu) + ffi (1.17.4-x86-linux-musl) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.9.0) + mutex_m + i18n (1.14.8) + concurrent-ruby (~> 1.0) + json (2.19.5) + logger (1.7.0) + minitest (5.27.0) + molinillo (0.8.0) + mutex_m (0.3.0) + nanaimo (0.4.0) + nap (1.1.0) + netrc (0.11.0) + public_suffix (4.0.7) + rexml (3.4.4) + ruby-macho (2.5.1) + securerandom (0.4.1) + typhoeus (1.6.0) + ethon (>= 0.18.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + xcodeproj (1.27.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.4.0) + rexml (>= 3.3.6, < 4.0) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + cocoapods + +RUBY VERSION + ruby 3.3.0p0 + +BUNDLED WITH + 2.5.3 diff --git a/LICENSE b/LICENSE index cb4203d..740d024 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2014 SCLAlertView-Objective-C by Diogo Autilio +Copyright (c) 2013-2023 SCLAlertView-Objective-C by Diogo Autilio Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..d7583bf --- /dev/null +++ b/Package.swift @@ -0,0 +1,26 @@ +// swift-tools-version:5.3 +import PackageDescription + +let package = Package( + name: "SCLAlertViewObjC", + platforms: [ + .iOS(.v12) + ], + products: [ + .library( + name: "SCLAlertViewObjC", + type: .dynamic, + targets: ["SCLAlertViewObjC"] + ) + ], + targets: [ + .target( + name: "SCLAlertViewObjC", + path: "SCLAlertView", + publicHeadersPath: ".", + cSettings: [ + .headerSearchPath("."), + ] + ) + ] +) diff --git a/README.md b/README.md index 1b00e19..001df7c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ SCLAlertView-Objective-C Animated Alert View written in Swift but ported to Objective-C, which can be used as a `UIAlertView` or `UIAlertController` replacement. -[![Build Status](https://travis-ci.org/dogo/SCLAlertView.svg?branch=master)](https://travis-ci.org/dogo/SCLAlertView) +![Build Status](https://github.com/dogo/SCLAlertView/workflows/Building/badge.svg) [![Cocoapods](http://img.shields.io/cocoapods/v/SCLAlertView-Objective-C.svg)](http://cocoapods.org/?q=SCLAlertView-Objective-C) [![Pod License](http://img.shields.io/cocoapods/l/SCLAlertView-Objective-C.svg)](https://github.com/dogo/SCLAlertView/blob/master/LICENSE) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) @@ -112,10 +112,6 @@ SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindowWidth:300.0f]; ``` -### New Window: Known issues - -1. SCLAlert animation is wrong in landscape. (iOS 6.X and 7.X) - ### Add buttons ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -182,7 +178,7 @@ alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] init]; -UITextField *textField = [alert addTextField:@"Enter your name"]; +UITextField *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; [alert addButton:@"Show Name" actionBlock:^(void) { NSLog(@"Text value: %@", textField.text); diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index db94af2..db00796 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "SCLAlertView-Objective-C" - spec.version = "1.1.3" + spec.version = "1.4.2" spec.summary = "Beautiful animated Alert View. Written in Swift but ported to Objective-C" spec.homepage = "https://github.com/dogo/SCLAlertView" spec.screenshots = "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png", "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png" @@ -10,7 +10,7 @@ Pod::Spec.new do |spec| spec.social_media_url = "http://twitter.com/di_autilio" spec.platform = :ios spec.frameworks = "UIKit", "AudioToolbox", "Accelerate", "CoreGraphics" - spec.ios.deployment_target = '6.0' + spec.ios.deployment_target = '12.0' spec.source = { :git => "https://github.com/dogo/SCLAlertView.git", :tag => spec.version.to_s } spec.source_files = "SCLAlertView/*" spec.requires_arc = true diff --git a/SCLAlertView.xcodeproj/project.pbxproj b/SCLAlertView.xcodeproj/project.pbxproj index 7178e22..92bf763 100644 --- a/SCLAlertView.xcodeproj/project.pbxproj +++ b/SCLAlertView.xcodeproj/project.pbxproj @@ -21,10 +21,18 @@ DD2E172A19FA84B800CBAEC3 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */; }; DD4B77E41D8C580B00CF97C7 /* SCLAlertViewFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 44E430DB1D889255002FE849 /* SCLAlertViewFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; DD4BA9C119DED8EF008D73EB /* right_answer.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DD4BA9C019DED8EF008D73EB /* right_answer.mp3 */; }; + DD5F3E112E954CB700E91C60 /* SCLAlertView+WindowResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = DD5F3E102E954CB400E91C60 /* SCLAlertView+WindowResolver.h */; }; + DD5F3E132E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */; }; + DD5F3E142E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */; }; DD7282B919D6087C00077F54 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DD7282B719D6087C00077F54 /* Storyboard.storyboard */; }; - DDB15FBD19D5B7C600173158 /* SCLAlertViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FBC19D5B7C600173158 /* SCLAlertViewTests.m */; }; - DDB15FCA19D5B88A00173158 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FC719D5B88A00173158 /* AppDelegate.m */; }; - DDB15FCB19D5B88A00173158 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FC919D5B88A00173158 /* ViewController.m */; }; + DDAD0113254DEABA00270C67 /* UIViewController+Alert.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD0111254DEABA00270C67 /* UIViewController+Alert.m */; }; + DDAD011D254DEAEC00270C67 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD0119254DEAEC00270C67 /* AppDelegate.m */; }; + DDAD011E254DEAEC00270C67 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD011B254DEAEC00270C67 /* ViewController.m */; }; + DDAA00012F00000100A11E57 /* SCLAlertViewTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA00072F00000100A11E57 /* SCLAlertViewTestHelpers.m */; }; + DDAA00022F00000100A11E57 /* SCLAlertViewButtonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA00082F00000100A11E57 /* SCLAlertViewButtonTests.m */; }; + DDAA00032F00000100A11E57 /* SCLAlertViewComponentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA00092F00000100A11E57 /* SCLAlertViewComponentTests.m */; }; + DDAA00042F00000100A11E57 /* SCLAlertViewPresentationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA000A2F00000100A11E57 /* SCLAlertViewPresentationTests.m */; }; + DDAA00052F00000100A11E57 /* SCLAlertViewBuilderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA000B2F00000100A11E57 /* SCLAlertViewBuilderTests.m */; }; DDB15FD019D5B8BF00173158 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDB15FCF19D5B8BF00173158 /* Images.xcassets */; }; DDB15FD419D5B8DB00173158 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FD319D5B8DB00173158 /* main.m */; }; DDB15FD719D5B96500173158 /* SCLAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FD619D5B96500173158 /* SCLAlertView.m */; }; @@ -72,15 +80,24 @@ DD2F03171AAFA4E0007BC507 /* SCLMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCLMacros.h; sourceTree = ""; }; DD4BA9C019DED8EF008D73EB /* right_answer.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = right_answer.mp3; sourceTree = ""; }; DD4BA9C219DEDD8E008D73EB /* SCLAlertView-Objective-C-prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SCLAlertView-Objective-C-prefix.pch"; path = "SCLAlertViewExample/SCLAlertView-Objective-C-prefix.pch"; sourceTree = SOURCE_ROOT; }; + DD5F3E102E954CB400E91C60 /* SCLAlertView+WindowResolver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SCLAlertView+WindowResolver.h"; sourceTree = ""; }; + DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SCLAlertView+WindowResolver.m"; sourceTree = ""; }; DD7282B819D6087C00077F54 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = SCLAlertViewExample/Base.lproj/Storyboard.storyboard; sourceTree = SOURCE_ROOT; }; + DDAD0111254DEABA00270C67 /* UIViewController+Alert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Alert.m"; sourceTree = ""; }; + DDAD0112254DEABA00270C67 /* UIViewController+Alert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Alert.h"; sourceTree = ""; }; + DDAD0118254DEAEC00270C67 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + DDAD0119254DEAEC00270C67 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + DDAD011B254DEAEC00270C67 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + DDAD011C254DEAEC00270C67 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; DDB15F9D19D5B7C600173158 /* SCLAlertView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SCLAlertView.app; sourceTree = BUILT_PRODUCTS_DIR; }; DDB15FB619D5B7C600173158 /* SCLAlertViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCLAlertViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DDB15FBB19D5B7C600173158 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DDB15FBC19D5B7C600173158 /* SCLAlertViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewTests.m; sourceTree = ""; }; - DDB15FC619D5B88A00173158 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = SCLAlertViewExample/AppDelegate.h; sourceTree = SOURCE_ROOT; }; - DDB15FC719D5B88A00173158 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = SCLAlertViewExample/AppDelegate.m; sourceTree = SOURCE_ROOT; }; - DDB15FC819D5B88A00173158 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ViewController.h; path = SCLAlertViewExample/ViewController.h; sourceTree = SOURCE_ROOT; }; - DDB15FC919D5B88A00173158 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ViewController.m; path = SCLAlertViewExample/ViewController.m; sourceTree = SOURCE_ROOT; }; + DDAA00062F00000100A11E57 /* SCLAlertViewTestHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCLAlertViewTestHelpers.h; sourceTree = ""; }; + DDAA00072F00000100A11E57 /* SCLAlertViewTestHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewTestHelpers.m; sourceTree = ""; }; + DDAA00082F00000100A11E57 /* SCLAlertViewButtonTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewButtonTests.m; sourceTree = ""; }; + DDAA00092F00000100A11E57 /* SCLAlertViewComponentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewComponentTests.m; sourceTree = ""; }; + DDAA000A2F00000100A11E57 /* SCLAlertViewPresentationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewPresentationTests.m; sourceTree = ""; }; + DDAA000B2F00000100A11E57 /* SCLAlertViewBuilderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewBuilderTests.m; sourceTree = ""; }; DDB15FCF19D5B8BF00173158 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SCLAlertViewExample/Images.xcassets; sourceTree = SOURCE_ROOT; }; DDB15FD319D5B8DB00173158 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SCLAlertViewExample/main.m; sourceTree = SOURCE_ROOT; }; DDB15FD619D5B96500173158 /* SCLAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCLAlertView.m; sourceTree = ""; }; @@ -147,6 +164,36 @@ path = SCLAlertViewExample/Sounds; sourceTree = SOURCE_ROOT; }; + DDAD0110254DEABA00270C67 /* Category */ = { + isa = PBXGroup; + children = ( + DDAD0111254DEABA00270C67 /* UIViewController+Alert.m */, + DDAD0112254DEABA00270C67 /* UIViewController+Alert.h */, + ); + name = Category; + path = SCLAlertViewExample/Category; + sourceTree = SOURCE_ROOT; + }; + DDAD0117254DEAEC00270C67 /* AppDelegate */ = { + isa = PBXGroup; + children = ( + DDAD0118254DEAEC00270C67 /* AppDelegate.h */, + DDAD0119254DEAEC00270C67 /* AppDelegate.m */, + ); + name = AppDelegate; + path = SCLAlertViewExample/AppDelegate; + sourceTree = SOURCE_ROOT; + }; + DDAD011A254DEAEC00270C67 /* ViewController */ = { + isa = PBXGroup; + children = ( + DDAD011C254DEAEC00270C67 /* ViewController.h */, + DDAD011B254DEAEC00270C67 /* ViewController.m */, + ); + name = ViewController; + path = SCLAlertViewExample/ViewController; + sourceTree = SOURCE_ROOT; + }; DDB15F9419D5B7C600173158 = { isa = PBXGroup; children = ( @@ -173,12 +220,11 @@ isa = PBXGroup; children = ( DDB15FCF19D5B8BF00173158 /* Images.xcassets */, - DDB15FC619D5B88A00173158 /* AppDelegate.h */, - DDB15FC719D5B88A00173158 /* AppDelegate.m */, - DDB15FC819D5B88A00173158 /* ViewController.h */, - DDB15FC919D5B88A00173158 /* ViewController.m */, - DDB15FA019D5B7C600173158 /* Supporting Files */, DD7282B719D6087C00077F54 /* Storyboard.storyboard */, + DDAD0117254DEAEC00270C67 /* AppDelegate */, + DDAD0110254DEABA00270C67 /* Category */, + DDB15FA019D5B7C600173158 /* Supporting Files */, + DDAD011A254DEAEC00270C67 /* ViewController */, ); name = SCLAlertViewExample; path = SCLAlertView; @@ -199,7 +245,12 @@ DDB15FB919D5B7C600173158 /* SCLAlertViewTests */ = { isa = PBXGroup; children = ( - DDB15FBC19D5B7C600173158 /* SCLAlertViewTests.m */, + DDAA00062F00000100A11E57 /* SCLAlertViewTestHelpers.h */, + DDAA00072F00000100A11E57 /* SCLAlertViewTestHelpers.m */, + DDAA00082F00000100A11E57 /* SCLAlertViewButtonTests.m */, + DDAA00092F00000100A11E57 /* SCLAlertViewComponentTests.m */, + DDAA000A2F00000100A11E57 /* SCLAlertViewPresentationTests.m */, + DDAA000B2F00000100A11E57 /* SCLAlertViewBuilderTests.m */, DDB15FBA19D5B7C600173158 /* Supporting Files */, ); path = SCLAlertViewTests; @@ -216,23 +267,25 @@ DDB15FD519D5B96500173158 /* SCLAlertView */ = { isa = PBXGroup; children = ( - DD2E172819FA84B800CBAEC3 /* UIImage+ImageEffects.h */, - DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */, DDB15FD819D5B98800173158 /* SCLAlertView.h */, DDB15FD619D5B96500173158 /* SCLAlertView.m */, - DDB15FD919D5BAA000173158 /* SCLButton.h */, - DDB15FDA19D5BAA000173158 /* SCLButton.m */, + DD5F3E102E954CB400E91C60 /* SCLAlertView+WindowResolver.h */, + DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */, DDB15FDC19D5BCF400173158 /* SCLAlertViewResponder.h */, DDB15FDD19D5BCF400173158 /* SCLAlertViewResponder.m */, DDB15FDF19D5D85B00173158 /* SCLAlertViewStyleKit.h */, DDB15FE019D5D85B00173158 /* SCLAlertViewStyleKit.m */, + DDB15FD919D5BAA000173158 /* SCLButton.h */, + DDB15FDA19D5BAA000173158 /* SCLButton.m */, DD2F03171AAFA4E0007BC507 /* SCLMacros.h */, - 572BB1451B8383B3002DEE38 /* SCLTimerDisplay.h */, - 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */, - DD24453A1BAC383600892117 /* SCLTextView.h */, - DD24453B1BAC383600892117 /* SCLTextView.m */, CF6FB1221C5926FC009715F3 /* SCLSwitchView.h */, CF6FB1231C5926FC009715F3 /* SCLSwitchView.m */, + DD24453A1BAC383600892117 /* SCLTextView.h */, + DD24453B1BAC383600892117 /* SCLTextView.m */, + 572BB1451B8383B3002DEE38 /* SCLTimerDisplay.h */, + 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */, + DD2E172819FA84B800CBAEC3 /* UIImage+ImageEffects.h */, + DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */, ); path = SCLAlertView; sourceTree = ""; @@ -267,6 +320,7 @@ 726C8FA81EF805620060F33B /* SCLTextView.h in Headers */, 726C8FA71EF805520060F33B /* SCLButton.h in Headers */, DD4B77E41D8C580B00CF97C7 /* SCLAlertViewFramework.h in Headers */, + DD5F3E112E954CB700E91C60 /* SCLAlertView+WindowResolver.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -332,11 +386,12 @@ DDB15F9519D5B7C600173158 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; + LastUpgradeCheck = 2600; ORGANIZATIONNAME = "AnyKey Entertainment"; TargetAttributes = { DDB15F9C19D5B7C600173158 = { CreatedOnToolsVersion = 6.0.1; + LastSwiftMigration = 1200; }; DDB15FB519D5B7C600173158 = { CreatedOnToolsVersion = 6.0.1; @@ -349,7 +404,7 @@ }; buildConfigurationList = DDB15F9819D5B7C600173158 /* Build configuration list for PBXProject "SCLAlertView" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -400,16 +455,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDAD011D254DEAEC00270C67 /* AppDelegate.m in Sources */, DD2E172A19FA84B800CBAEC3 /* UIImage+ImageEffects.m in Sources */, - DDB15FCB19D5B88A00173158 /* ViewController.m in Sources */, DDB15FD419D5B8DB00173158 /* main.m in Sources */, CF6FB1241C5926FC009715F3 /* SCLSwitchView.m in Sources */, DDB15FE119D5D85B00173158 /* SCLAlertViewStyleKit.m in Sources */, + DDAD0113254DEABA00270C67 /* UIViewController+Alert.m in Sources */, + DDAD011E254DEAEC00270C67 /* ViewController.m in Sources */, DD24453C1BAC383600892117 /* SCLTextView.m in Sources */, 572BB1471B8383B3002DEE38 /* SCLTimerDisplay.m in Sources */, DDB15FD719D5B96500173158 /* SCLAlertView.m in Sources */, + DD5F3E132E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */, DDB15FDB19D5BAA000173158 /* SCLButton.m in Sources */, - DDB15FCA19D5B88A00173158 /* AppDelegate.m in Sources */, DDB15FDE19D5BCF400173158 /* SCLAlertViewResponder.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -418,7 +475,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DDB15FBD19D5B7C600173158 /* SCLAlertViewTests.m in Sources */, + DDAA00012F00000100A11E57 /* SCLAlertViewTestHelpers.m in Sources */, + DDAA00022F00000100A11E57 /* SCLAlertViewButtonTests.m in Sources */, + DDAA00032F00000100A11E57 /* SCLAlertViewComponentTests.m in Sources */, + DDAA00042F00000100A11E57 /* SCLAlertViewPresentationTests.m in Sources */, + DDAA00052F00000100A11E57 /* SCLAlertViewBuilderTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -428,6 +489,7 @@ files = ( EF994B191D47AB4A00619DFF /* SCLAlertViewStyleKit.m in Sources */, EF994B1C1D47AB4A00619DFF /* SCLSwitchView.m in Sources */, + DD5F3E142E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */, EF994B1A1D47AB4A00619DFF /* SCLTimerDisplay.m in Sources */, EF994B161D47AB4A00619DFF /* SCLAlertView.m in Sources */, EF994B181D47AB4A00619DFF /* SCLAlertViewResponder.m in Sources */, @@ -471,14 +533,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -503,7 +568,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -523,14 +588,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -548,7 +616,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -561,11 +629,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = "$(SRCROOT)/SCLAlertViewExample/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -574,11 +645,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = "$(SRCROOT)/SCLAlertViewExample/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -595,6 +668,7 @@ "$(inherited)", ); INFOPLIST_FILE = SCLAlertViewTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -611,6 +685,7 @@ "$(inherited)", ); INFOPLIST_FILE = SCLAlertViewTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -632,11 +707,13 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SCLAlertViewFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = br.com.anykey.SCLAlertViewFramework; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -657,11 +734,13 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SCLAlertViewFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = br.com.anykey.SCLAlertViewFramework; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; + TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/SCLAlertView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SCLAlertView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/SCLAlertView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme new file mode 100644 index 0000000..a33ed47 --- /dev/null +++ b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme index dc021f3..bc11bcf 100644 --- a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme +++ b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme @@ -1,6 +1,6 @@ - - - - + +@implementation SCLAlertView (WindowResolver) + ++ (UIWindow *)scl_currentKeyWindow { + UIApplication *app = UIApplication.sharedApplication; + if (@available(iOS 13.0, *)) { + for (UIScene *scene in app.connectedScenes) { + if (scene.activationState == UISceneActivationStateForegroundActive && + [scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *ws = (UIWindowScene *)scene; + for (UIWindow *w in ws.windows) { + if (w.isKeyWindow) return w; + } + if (ws.windows.firstObject) return ws.windows.firstObject; + } + } + for (UIScene *scene in app.connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *ws = (UIWindowScene *)scene; + if (ws.windows.firstObject) return ws.windows.firstObject; + } + } + return nil; + } else { + return app.keyWindow; + } +} + ++ (UIView *)scl_resolveAppViewWithFallback:(UIView *)fallback { + UIWindow *key = [self scl_currentKeyWindow]; + if (key) return key; + return fallback; +} + +@end diff --git a/SCLAlertView/SCLAlertView.h b/SCLAlertView/SCLAlertView.h index 5868b62..2b88841 100755 --- a/SCLAlertView/SCLAlertView.h +++ b/SCLAlertView/SCLAlertView.h @@ -3,30 +3,25 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif #import "SCLButton.h" #import "SCLTextView.h" #import "SCLSwitchView.h" -typedef NSAttributedString* (^SCLAttributedFormatBlock)(NSString *value); +NS_ASSUME_NONNULL_BEGIN + +typedef NSAttributedString* _Nonnull (^SCLAttributedFormatBlock)(NSString *value); typedef void (^SCLDismissBlock)(void); typedef void (^SCLDismissAnimationCompletionBlock)(void); typedef void (^SCLShowAnimationCompletionBlock)(void); typedef void (^SCLForceHideBlock)(void); -@interface SCLAlertView : UIViewController +@interface SCLAlertView : UIViewController -/** Alert Styles - * - * Set SCLAlertView Style - */ +/** Predefined alert styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewStyle) { SCLAlertViewStyleSuccess, @@ -40,10 +35,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewStyle) SCLAlertViewStyleCustom }; -/** Alert hide animation styles - * - * Set SCLAlertView hide animation type. - */ +/** Hide animation styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) { SCLAlertViewHideAnimationFadeOut, @@ -56,10 +48,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) SCLAlertViewHideAnimationSimplyDisappear }; -/** Alert show animation styles - * - * Set SCLAlertView show animation type. - */ +/** Show animation styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) { SCLAlertViewShowAnimationFadeIn, @@ -72,10 +61,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) SCLAlertViewShowAnimationSimplyAppear }; -/** Alert background styles - * - * Set SCLAlertView background type. - */ +/** Background styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) { SCLAlertViewBackgroundShadow, @@ -83,401 +69,397 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) SCLAlertViewBackgroundTransparent }; -/** Content view corner radius - * - * A float value that replaces the standard content viuew corner radius. - */ +/// Overrides the content view corner radius. @property CGFloat cornerRadius; -/** Tint top circle - * - * A boolean value that determines whether to tint the SCLAlertView top circle. - * (Default: YES) - */ +/// Whether the top circle is tinted with the alert color. (Default: YES) @property (assign, nonatomic) BOOL tintTopCircle; -/** Use larger icon - * - * A boolean value that determines whether to make the SCLAlertView top circle icon larger. - * (Default: NO) - */ +/// Whether to use a larger icon in the top circle. (Default: NO) @property (assign, nonatomic) BOOL useLargerIcon; - -/** Title Label - * - * The text displayed as title. - */ -@property (strong, nonatomic) UILabel *labelTitle; -/** Text view with the body message - * - * Holds the textview. - */ -@property (strong, nonatomic) UITextView *viewText; +/// Title label displayed at the top of the alert. +@property (strong, nonatomic, nullable) UILabel *labelTitle; -/** Activity Indicator - * - * Holds the activityIndicator. - */ -@property (strong, nonatomic) UIActivityIndicatorView *activityIndicatorView; +/// Text view containing the message body. +@property (strong, nonatomic, nullable) UITextView *viewText; -/** Dismiss on tap outside - * - * A boolean value that determines whether to dismiss when tapping outside the SCLAlertView. - * (Default: NO) - */ +/// Activity indicator used for Waiting style. +@property (strong, nonatomic, nullable) UIActivityIndicatorView *activityIndicatorView; + +/// If YES, tapping outside the alert dismisses it. (Default: NO) @property (assign, nonatomic) BOOL shouldDismissOnTapOutside; -/** Sound URL - * - * Holds the sound NSURL path. - */ -@property (strong, nonatomic) NSURL *soundURL; +/// URL of the sound to play. +@property (strong, nonatomic, nullable) NSURL *soundURL; -/** Set text attributed format block - * - * Holds the attributed string. - */ -@property (copy, nonatomic) SCLAttributedFormatBlock attributedFormatBlock; +/// Provides an attributed string for the body text. +@property (copy, nonatomic, nullable) SCLAttributedFormatBlock attributedFormatBlock; -/** Set Complete button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor - */ -@property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; +/// Provides full button styling (backgroundColor, borderWidth, borderColor, textColor). +@property (copy, nonatomic, nullable) CompleteButtonFormatBlock completeButtonFormatBlock; -/** Set button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor - */ -@property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; +/// Provides button styling (backgroundColor, borderWidth, borderColor, textColor). +@property (copy, nonatomic, nullable) ButtonFormatBlock buttonFormatBlock; -/** Set force hide block. - * - * When set force hideview method invocation. - */ -@property (copy, nonatomic) SCLForceHideBlock forceHideBlock; +/// If set, calling this property triggers hideView. +@property (copy, nonatomic, nullable) SCLForceHideBlock forceHideBlock; -/** Hide animation type - * - * Holds the hide animation type. - * (Default: FadeOut) - */ +/// Hide animation type. (Default: FadeOut) @property (nonatomic) SCLAlertViewHideAnimation hideAnimationType; -/** Show animation type - * - * Holds the show animation type. - * (Default: SlideInFromTop) - */ +/// Show animation type. (Default: SlideInFromTop) @property (nonatomic) SCLAlertViewShowAnimation showAnimationType; -/** Set SCLAlertView background type. - * - * SCLAlertView background type. - * (Default: Shadow) - */ +/// Background effect behind the alert. (Default: Shadow) @property (nonatomic) SCLAlertViewBackground backgroundType; -/** Set custom color to SCLAlertView. - * - * SCLAlertView custom color. - * (Buttons, top circle and borders) - */ -@property (strong, nonatomic) UIColor *customViewColor; +/// Custom alert color (buttons, top circle, borders). +@property (strong, nonatomic, nullable) UIColor *customViewColor; -/** Set custom color to SCLAlertView background. - * - * SCLAlertView background custom color. - */ -@property (strong, nonatomic) UIColor *backgroundViewColor; +/// Custom background view color. +@property (strong, nonatomic, nullable) UIColor *backgroundViewColor; -/** Set custom tint color for icon image. - * - * SCLAlertView icon tint color - */ -@property (strong, nonatomic) UIColor *iconTintColor; +/// Tint color for the icon image. +@property (strong, nonatomic, nullable) UIColor *iconTintColor; -/** Set custom circle icon height. - * - * Circle icon height - */ +/// Custom size for the icon inside the top circle. @property (nonatomic) CGFloat circleIconHeight; -/** Set SCLAlertView extension bounds. - * - * Set new bounds (EXTENSION ONLY) - */ +/// New bounds to use when running as an app extension only. @property (nonatomic) CGRect extensionBounds; -/** Set status bar hidden. - * - * Status bar hidden - */ +/// Status bar hidden state. @property (nonatomic) BOOL statusBarHidden; -/** Set status bar style. - * - * Status bar style - */ +/// Status bar style. @property (nonatomic) UIStatusBarStyle statusBarStyle; -/** Set horizontal alignment for buttons - * - * Horizontal aligment instead of vertically if YES - */ +/// If YES, buttons are laid out horizontally instead of vertically. @property (nonatomic) BOOL horizontalButtons; -/** Initialize SCLAlertView using a new window. - * - * Init with new window +#pragma mark - Initializers + +/** + Initializes an alert with a specific width. + + @param width The desired alert width. + @return An initialized SCLAlertView instance. + */ +- (instancetype)initWithWidth:(CGFloat)width; + +/** + Initializes an alert presented in a new UIWindow. + + @return An initialized SCLAlertView instance. */ - (instancetype)initWithNewWindow; -/** Initialize SCLAlertView using a new window. - * - * Init with new window with custom width +/** + Creates and returns a new alert configured to present in its own UIWindow. + + This convenience constructor is equivalent to [[SCLAlertView alloc] initWithNewWindow]. + + @return A newly created SCLAlertView instance ready to be shown in a dedicated window. + @note In Swift, use SCLAlertView.newWindow() due to NS_SWIFT_NAME(newWindow()). + */ ++ (instancetype)alertWithNewWindow NS_SWIFT_NAME(newWindow()); + +/** + Initializes an alert presented in a new UIWindow with custom width. + + @param windowWidth The desired alert width. + @return An initialized SCLAlertView instance. */ - (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth; -/** Warns that alerts is gone - * - * Warns that alerts is gone using block +#pragma mark - Callbacks + +/** + Sets a block to be called when the alert is dismissed. + + @param dismissBlock The block executed upon dismissal. */ - (void)alertIsDismissed:(SCLDismissBlock)dismissBlock; -/** Warns that alerts dismiss animation is completed - * - * Warns that alerts dismiss animation is completed +/** + Sets a block to be called when the dismiss animation completes. + + @param dismissAnimationCompletionBlock The completion block. */ - (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock; -/** Warns that alerts show animation is completed - * - * Warns that alerts show animation is completed +/** + Sets a block to be called when the show animation completes. + + @param showAnimationCompletionBlock The completion block. */ - (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock; -/** Hide SCLAlertView - * - * Hide SCLAlertView using animation and removing from super view. - */ +#pragma mark - Visibility +/** + Hides the alert with animation and removes it from the view hierarchy. + */ - (void)hideView; -/** SCLAlertView visibility - * - * Returns if the alert is visible or not. +/** + Returns whether the alert is visible. + + @return YES if visible; otherwise NO. */ - (BOOL)isVisible; -/** Remove Top Circle - * - * Remove top circle from SCLAlertView. +/** + Removes the top circle from the alert. */ - (void)removeTopCircle; -/** Add a custom UIView - * - * @param customView UIView object to be added above the first SCLButton. +#pragma mark - Content + +/** + Adds a custom view above the first button. + + @param customView The UIView to add. + @return The same customView for chaining. */ - (UIView *)addCustomView:(UIView *)customView; -/** Add Text Field - * - * @param title The text displayed on the textfield. +/** + Adds a text field with optional default text. + + @param title The placeholder text for the text field. + @param defaultText Optional default text. + @return The created SCLTextView. */ -- (SCLTextView *)addTextField:(NSString *)title; +- (SCLTextView *)addTextField:(NSString *)title setDefaultText:(nullable NSString *)defaultText; -/** Add a custom Text Field - * - * @param textField The custom textfield provided by the programmer. +/** + Adds a custom text field. + + @param textField The custom UITextField instance. */ - (void)addCustomTextField:(UITextField *)textField; -/** Add a switch view - * - * @param label The label displayed for the switch. +/** + Adds a switch view with an optional label. + + @param label The label text for the switch. + @return The created SCLSwitchView. */ -- (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label; +- (SCLSwitchView *)addSwitchViewWithLabel:(nullable NSString *)label; + +#pragma mark - Timer -/** Add Timer Display - * - * @param buttonIndex The index of the button to add the timer display to. - * @param reverse Convert timer to countdown. +/** + Adds a circular timer to a button. + + @param buttonIndex Index of the button to attach the timer to. + @param reverse If YES, shows a countdown. */ - (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse; -/** Set Title font family and size - * - * @param titleFontFamily The family name used to displayed the title. - * @param size Font size. +#pragma mark - Fonts + +/** + Sets the title font family and size. + + @param titleFontFamily The font family name. + @param size The font size. */ - (void)setTitleFontFamily:(NSString *)titleFontFamily withSize:(CGFloat)size; -/** Set Text field font family and size - * - * @param bodyTextFontFamily The family name used to displayed the text field. - * @param size Font size. +/** + Sets the body text font family and size. + + @param bodyTextFontFamily The font family name. + @param size The font size. */ - (void)setBodyTextFontFamily:(NSString *)bodyTextFontFamily withSize:(CGFloat)size; -/** Set Buttons font family and size - * - * @param buttonsFontFamily The family name used to displayed the buttons. - * @param size Font size. +/** + Sets the buttons font family and size. + + @param buttonsFontFamily The font family name. + @param size The font size. */ - (void)setButtonsTextFontFamily:(NSString *)buttonsFontFamily withSize:(CGFloat)size; -/** Add a Button with a title and a block to handle when the button is pressed. - * - * @param title The text displayed on the button. - * @param action A block of code to be executed when the button is pressed. +#pragma mark - Buttons + +/** + Adds a button with a title and action block. + + @param title The button title. + @param action The block executed when the button is tapped. + @return The created SCLButton. */ - (SCLButton *)addButton:(NSString *)title actionBlock:(SCLActionBlock)action; -/** Add a Button with a title, a block to handle validation, and a block to handle when the button is pressed and validation succeeds. - * - * @param title The text displayed on the button. - * @param validationBlock A block of code that will allow you to validate fields or do any other logic you may want to do to determine if the alert should be dismissed or not. Inside of this block, return a BOOL indicating whether or not the action block should be called and the alert dismissed. - * @param action A block of code to be executed when the button is pressed and validation passes. +/** + Adds a button with validation and action blocks. + + @param title The button title. + @param validationBlock A block returning YES to proceed and dismiss, NO to keep the alert. + @param action The block executed when validation passes and the button is tapped. + @return The created SCLButton. */ - (SCLButton *)addButton:(NSString *)title validationBlock:(SCLValidationBlock)validationBlock actionBlock:(SCLActionBlock)action; -/** Add a Button with a title, a target and a selector to handle when the button is pressed. - * - * @param title The text displayed on the button. - * @param target Add target for particular event. - * @param selector A method to be executed when the button is pressed. +/** + Adds a button with a target and selector. + + @param title The button title. + @param target The target object for the selector. + @param selector The selector to invoke on tap. + @return The created SCLButton. */ - (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selector; -/** Show Success SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +#pragma mark - Show (predefined styles) + +/** + Shows a Success alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Error SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows an Error alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showError:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Notice SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showError:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Notice alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showNotice:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Warning SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showNotice:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Warning alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showWarning:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Info SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showWarning:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows an Info alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showInfo:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Edit SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showInfo:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows an Edit alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showEdit:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Title SCLAlertView using a predefined type - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param style One of predefined SCLAlertView styles. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showEdit:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +#pragma mark - Show (custom) + +/** + Shows a predefined style alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param style The predefined style. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Shows a custom SCLAlertView without using a predefined type, allowing for a custom image and color to be specified. - * - * @param vc The view controller the alert view will be displayed in. - * @param image A UIImage object to be used as the icon for the alert view. - * @param color A UIColor object to be used to tint the background of the icon circle and the buttons. - * @param title The title text of the alert view. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a custom alert with custom image and color. + + @param vc The presenting view controller. + @param image The icon image. + @param color The primary color (buttons, top circle, borders). + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showCustom:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Waiting SCLAlertView with UIActityIndicator. - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showCustom:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Waiting alert with UIActivityIndicator. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showWaiting:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; - -/** Show Question SCLAlertView - * - * @param vc The view controller the alert view will be displayed in. - * @param title The text displayed on the button. - * @param subTitle The subtitle text of the alert view. - * @param closeButtonTitle The text for the close button. - * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. +- (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showWaiting:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Question alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; -- (void)showQuestion:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showQuestion:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +@end +@protocol SCLItemsBuilder__Protocol__Fluent +- (void)setupFluent; @end -@interface SCLAlertViewShowBuilder : NSObject +@interface SCLAlertViewBuilder__WithFluent: NSObject @end -@property(weak, nonatomic, readonly) UIViewController *parameterViewController; -@property(copy, nonatomic, readonly) UIImage *parameterImage; -@property(copy, nonatomic, readonly) UIColor *parameterColor; -@property(copy, nonatomic, readonly) NSString *parameterTitle; -@property(copy, nonatomic, readonly) NSString *parameterSubTitle; -@property(copy, nonatomic, readonly) NSString *parameterCompleteText; -@property(copy, nonatomic, readonly) NSString *parameterCloseButtonTitle; +@interface SCLAlertViewShowBuilder : SCLAlertViewBuilder__WithFluent + +@property(weak, nonatomic, readonly, nullable) UIViewController *parameterViewController; +@property(copy, nonatomic, readonly, nullable) UIImage *parameterImage; +@property(copy, nonatomic, readonly, nullable) UIColor *parameterColor; +@property(copy, nonatomic, readonly, nullable) NSString *parameterTitle; +@property(copy, nonatomic, readonly, nullable) NSString *parameterSubTitle; +@property(copy, nonatomic, readonly, nullable) NSString *parameterCompleteText; +@property(copy, nonatomic, readonly, nullable) NSString *parameterCloseButtonTitle; @property(assign, nonatomic, readonly) SCLAlertViewStyle parameterStyle; @property(assign, nonatomic, readonly) NSTimeInterval parameterDuration; @@ -493,24 +475,24 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^duration)(NSTimeInterval duration); - (void)showAlertView:(SCLAlertView *)alertView; -- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController *)controller; -@property(copy, nonatomic, readonly) void (^show)(SCLAlertView *view, UIViewController *controller); +- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController * _Nullable)controller; +@property(copy, nonatomic, readonly) void (^show)(SCLAlertView *view, UIViewController * _Nullable controller); @end -@interface SCLALertViewTextFieldBuilder : NSObject +@interface SCLALertViewTextFieldBuilder : SCLAlertViewBuilder__WithFluent #pragma mark - Available later after adding -@property(weak, nonatomic, readonly) SCLTextView *textField; +@property(weak, nonatomic, readonly, nullable) SCLTextView *textField; #pragma mark - Setters @property(copy, nonatomic, readonly) SCLALertViewTextFieldBuilder *(^title) (NSString *title); @end -@interface SCLALertViewButtonBuilder : NSObject +@interface SCLALertViewButtonBuilder : SCLAlertViewBuilder__WithFluent #pragma mark - Available later after adding -@property(weak, nonatomic, readonly) SCLButton *button; +@property(weak, nonatomic, readonly, nullable) SCLButton *button; #pragma mark - Setters @property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^title) (NSString *title); @@ -521,7 +503,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @end -@interface SCLAlertViewBuilder : NSObject +@interface SCLAlertViewBuilder : SCLAlertViewBuilder__WithFluent #pragma mark - Parameters @property (strong, nonatomic, readonly) SCLAlertView *alertView; @@ -561,9 +543,9 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @property(copy, nonatomic) SCLAlertViewBuilder *(^alertShowAnimationIsCompleted) (SCLShowAnimationCompletionBlock showAnimationCompletionBlock); @property(copy, nonatomic) SCLAlertViewBuilder *(^removeTopCircle)(void); @property(copy, nonatomic) SCLAlertViewBuilder *(^addCustomView)(UIView *view); -@property(copy, nonatomic) SCLAlertViewBuilder *(^addTextField)(NSString *title); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addTextField)(NSString *title, NSString * _Nullable defaultText); @property(copy, nonatomic) SCLAlertViewBuilder *(^addCustomTextField)(UITextField *textField); -@property(copy, nonatomic) SCLAlertViewBuilder *(^addSwitchViewWithLabelTitle)(NSString *title); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addSwitchViewWithLabelTitle)(NSString * _Nullable title); @property(copy, nonatomic) SCLAlertViewBuilder *(^addTimerToButtonIndex)(NSInteger buttonIndex, BOOL reverse); @property(copy, nonatomic) SCLAlertViewBuilder *(^setTitleFontFamily)(NSString *titleFontFamily, CGFloat size); @property(copy, nonatomic) SCLAlertViewBuilder *(^setBodyTextFontFamily)(NSString *bodyTextFontFamily, CGFloat size); @@ -577,3 +559,5 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @property(copy, nonatomic) SCLAlertViewBuilder *(^addTextFieldWithBuilder)(SCLALertViewTextFieldBuilder *builder); @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 16284dd..3d69d55 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -3,26 +3,20 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // #import "SCLAlertView.h" #import "SCLAlertViewResponder.h" #import "SCLAlertViewStyleKit.h" #import "UIImage+ImageEffects.h" +#import "SCLAlertView+WindowResolver.h" #import "SCLTimerDisplay.h" #import "SCLMacros.h" -#if defined(__has_feature) && __has_feature(modules) @import AVFoundation; @import AudioToolbox; -#else -#import -#import -#endif -#define KEYBOARD_HEIGHT 80 -#define PREDICTION_BAR_HEIGHT 40 #define ADD_BUTTON_PADDING 10.0f #define DEFAULT_WINDOW_WIDTH 240 @@ -62,6 +56,9 @@ @interface SCLAlertView () @property (nonatomic) CGFloat subTitleHeight; @property (nonatomic) CGFloat subTitleY; +@property (nonatomic) CGPoint tmpContentViewFrameOrigin; +@property (nonatomic) CGPoint tmpCircleViewFrameOrigin; + @end @implementation SCLAlertView @@ -96,6 +93,16 @@ - (instancetype)init return self; } +- (instancetype)initWithWidth:(CGFloat)width +{ + self = [super init]; + if (self) + { + [self setupViewWindowWidth:width]; + } + return self; +} + - (instancetype)initWithWindowWidth:(CGFloat)windowWidth { self = [super init]; @@ -116,6 +123,11 @@ - (instancetype)initWithNewWindow return self; } ++ (instancetype)alertWithNewWindow +{ + return [[self alloc] initWithNewWindow]; +} + - (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth { self = [self initWithWindowWidth:windowWidth]; @@ -132,6 +144,8 @@ - (void)dealloc [self restoreInteractivePopGesture]; } +#pragma mark - Observers + - (void)addObservers { if(_canAddObservers) @@ -148,7 +162,7 @@ - (void)removeObservers [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } -#pragma mark - Setup view +#pragma mark - Setup View - (void)setupViewWindowWidth:(CGFloat)windowWidth { @@ -173,7 +187,7 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth self.backgroundType = SCLAlertViewBackgroundShadow; self.tintTopCircle = YES; - // Font + // Fonts _titleFontFamily = @"HelveticaNeue"; _bodyTextFontFamily = @"HelveticaNeue"; _buttonsFontFamily = @"HelveticaNeue-Bold"; @@ -195,28 +209,28 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth _customViews = [[NSMutableArray alloc] init]; self.view.accessibilityViewIsModal = YES; - // Add Subviews + // Add subviews [self.view addSubview:_contentView]; [self.view addSubview:_circleViewBackground]; - // Circle View + // Circle view CGFloat x = (kCircleHeightBackground - kCircleHeight) / 2; _circleView.frame = CGRectMake(x, x, kCircleHeight, kCircleHeight); _circleView.layer.cornerRadius = _circleView.frame.size.height / 2; - // Circle Background View + // Circle background view _circleViewBackground.backgroundColor = [UIColor whiteColor]; _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; x = (kCircleHeight - _circleIconHeight) / 2; - // Circle Image View + // Circle image view _circleIconImageView.frame = CGRectMake(x, x, _circleIconHeight, _circleIconHeight); _circleIconImageView.contentMode = UIViewContentModeScaleAspectFill; [_circleViewBackground addSubview:_circleView]; [_circleView addSubview:_circleIconImageView]; - // Background View + // Background view _backgroundView.userInteractionEnabled = YES; // Title @@ -226,45 +240,61 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth _labelTitle.font = [UIFont fontWithName:_titleFontFamily size:_titleFontSize]; _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, _titleHeight); - // View text + // Body text _viewText.editable = NO; _viewText.allowsEditingTextAttributes = YES; _viewText.textAlignment = NSTextAlignmentCenter; _viewText.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize]; _viewText.frame = CGRectMake(12.0f, _subTitleY, _windowWidth - 24.0f, _subTitleHeight); + _viewText.textContainerInset = UIEdgeInsetsZero; + _viewText.textContainer.lineFragmentPadding = 0; + _viewText.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) - { - _viewText.textContainerInset = UIEdgeInsetsZero; - _viewText.textContainer.lineFragmentPadding = 0; - self.automaticallyAdjustsScrollViewInsets = NO; - } - - // Content View + // Content view _contentView.backgroundColor = [UIColor whiteColor]; _contentView.layer.cornerRadius = 5.0f; _contentView.layer.masksToBounds = YES; _contentView.layer.borderWidth = 0.5f; - [_contentView addSubview:_viewText]; + [_contentView addSubview:_viewText]; [_contentView addSubview:_labelTitle]; // Colors self.backgroundViewColor = [UIColor whiteColor]; - _labelTitle.textColor = UIColorFromHEX(0x4D4D4D); //Dark Grey - _viewText.textColor = UIColorFromHEX(0x4D4D4D); //Dark Grey - _contentView.layer.borderColor = UIColorFromHEX(0xCCCCCC).CGColor; //Light Grey + _labelTitle.textColor = UIColorFromHEX(0x4D4D4D); // Dark gray + _viewText.textColor = UIColorFromHEX(0x4D4D4D); // Dark gray + _contentView.layer.borderColor = UIColorFromHEX(0xCCCCCC).CGColor; // Light gray } -- (void)setupNewWindow { - // Save previous window - self.previousWindow = [UIApplication sharedApplication].keyWindow; - - // Create a new one to show the alert +- (void)setupNewWindow +{ + // Preserve the current key window to restore it after dismissing the alert + self.previousWindow = [SCLAlertView scl_currentKeyWindow]; + + // Create a dedicated window to host the alert UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[self mainScreenFrame]]; alertWindow.windowLevel = UIWindowLevelAlert; alertWindow.backgroundColor = [UIColor clearColor]; alertWindow.rootViewController = [UIViewController new]; alertWindow.accessibilityViewIsModal = YES; + + // On iOS 13+, explicitly attach the alert window to the active UIWindowScene + if (@available(iOS 13.0, *)) { + // Try to reuse the scene from the current key window, if available + UIWindow *key = [SCLAlertView scl_currentKeyWindow]; + if (key.windowScene != nil) { + alertWindow.windowScene = key.windowScene; + } else { + // Fallback: iterate through connected scenes and pick a foreground active UIWindowScene + for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { + if (scene.activationState == UISceneActivationStateForegroundActive && + [scene isKindOfClass:[UIWindowScene class]]) { + alertWindow.windowScene = (UIWindowScene *)scene; + break; + } + } + } + } + self.SCLAlertWindow = alertWindow; self.usingNewWindow = YES; } @@ -275,7 +305,7 @@ - (BOOL)isModal { return (_rootViewController != nil && _rootViewController.presentingViewController); } -#pragma mark - View Cycle +#pragma mark - View Lifecycle - (void)viewWillLayoutSubviews { @@ -303,20 +333,12 @@ - (void)viewWillLayoutSubviews kCircleBackgroundTopPosition = -(kCircleHeightBackground / 2); } - // Check if the rootViewController is modal, if so we need to get the modal size not the main screen size + // Use modal size if presented modally (and not using a new window) if ([self isModal] && !_usingNewWindow) { sz = _rootViewController.view.frame.size; } - if (SYSTEM_VERSION_LESS_THAN(@"8.0")) { - // iOS versions before 7.0 did not switch the width and height on device roration - if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) { - CGSize ssz = sz; - sz = CGSizeMake(ssz.height, ssz.width); - } - } - - // Set new main frame + // Set main frame CGRect r; if (self.view.superview != nil) { // View is showing, position at center of screen @@ -327,12 +349,12 @@ - (void)viewWillLayoutSubviews } self.view.frame = r; - // Set new background frame + // Background frame CGRect newBackgroundFrame = self.backgroundView.frame; newBackgroundFrame.size = sz; self.backgroundView.frame = newBackgroundFrame; - // Set frames + // Frames _contentView.frame = CGRectMake(0.0f, 0.0f, _windowWidth, _windowHeight); _circleViewBackground.frame = CGRectMake(_windowWidth / 2 - kCircleHeightBackground / 2, kCircleBackgroundTopPosition, kCircleHeightBackground, kCircleHeightBackground); _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; @@ -366,7 +388,7 @@ - (void)viewWillLayoutSubviews for (SCLButton *btn in _buttons) { btn.frame = CGRectMake(x, y, btn.frame.size.width, btn.frame.size.height); - // Add horizontal or vertical offset acording on _horizontalButtons parameter + // Add horizontal or vertical offset according to _horizontalButtons if (_horizontalButtons) { x += btn.frame.size.width + 10.0f; } else { @@ -378,11 +400,11 @@ - (void)viewWillLayoutSubviews self.windowHeight = _useLargerIcon ? y : self.windowHeight; _contentView.frame = CGRectMake(_contentView.frame.origin.x, _contentView.frame.origin.y, _windowWidth, _windowHeight); - // Adjust corner radius, if a value has been passed + // Adjust corner radius (if a value has been passed) _contentView.layer.cornerRadius = self.cornerRadius ? self.cornerRadius : 5.0f; } -#pragma mark - UIViewController +#pragma mark - Status Bar - (BOOL)prefersStatusBarHidden { @@ -394,7 +416,7 @@ - (UIStatusBarStyle)preferredStatusBarStyle return self.statusBarStyle; } -#pragma mark - Handle gesture +#pragma mark - Gesture Handling - (void)handleTap:(UITapGestureRecognizer *)gesture { @@ -404,7 +426,7 @@ - (void)handleTap:(UITapGestureRecognizer *)gesture for(SCLTextView *txt in _inputs) { - // Check if there is any keyboard on screen and dismiss + // Dismiss keyboard if any input is editing if (txt.editing) { [txt resignFirstResponder]; @@ -429,6 +451,8 @@ - (void)setShouldDismissOnTapOutside:(BOOL)shouldDismissOnTapOutside } } +#pragma mark - Navigation Gesture + - (void)disableInteractivePopGesture { UINavigationController *navigationController; @@ -442,7 +466,7 @@ - (void)disableInteractivePopGesture navigationController = _rootViewController.navigationController; } - // Disable iOS 7 back gesture + // Disable back gesture if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { _restoreInteractivePopGestureEnabled = navigationController.interactivePopGestureRecognizer.enabled; @@ -465,7 +489,7 @@ - (void)restoreInteractivePopGesture navigationController = _rootViewController.navigationController; } - // Restore iOS 7 back gesture + // Restore back gesture if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { navigationController.interactivePopGestureRecognizer.enabled = _restoreInteractivePopGestureEnabled; @@ -511,12 +535,12 @@ - (void)setSoundURL:(NSURL *)soundURL { _soundURL = soundURL; - //DisposeSound + // Dispose previous sound AudioServicesDisposeSystemSoundID(_soundID); AudioServicesCreateSystemSoundID((__bridge CFURLRef)_soundURL, &_soundID); - //PlaySound + // Play new sound AudioServicesPlaySystemSound(_soundID); } @@ -527,7 +551,7 @@ - (void)setSubTitleHeight:(CGFloat)value _subTitleHeight = value; } -#pragma mark - ActivityIndicator +#pragma mark - Activity Indicator - (void)addActivityIndicatorView { @@ -537,7 +561,7 @@ - (void)addActivityIndicatorView [_circleView addSubview:_activityIndicatorView]; } -#pragma mark - UICustomView +#pragma mark - Custom View - (UIView *)addCustomView:(UIView *)customView { @@ -550,7 +574,7 @@ - (UIView *)addCustomView:(UIView *)customView return customView; } -#pragma mark - SwitchView +#pragma mark - Switch View - (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label { @@ -571,9 +595,9 @@ - (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label return switchView; } -#pragma mark - TextField +#pragma mark - Text Field -- (SCLTextView *)addTextField:(NSString *)title +- (SCLTextView *)addTextField:(NSString *)title setDefaultText:(NSString *)defaultText { [self addObservers]; @@ -589,12 +613,15 @@ - (SCLTextView *)addTextField:(NSString *)title { txt.placeholder = title; } + if (defaultText != nil) + { + txt.text = defaultText; + } [_contentView addSubview:txt]; [_inputs addObject:txt]; - // If there are other fields in the inputs array, get the previous field and set the - // return key type on that to next. + // If there are other fields in the inputs array, set the previous field return key to Next if (_inputs.count > 1) { NSUInteger indexOfCurrentField = [_inputs indexOfObject:txt]; @@ -612,8 +639,7 @@ - (void)addCustomTextField:(UITextField *)textField [_contentView addSubview:textField]; [_inputs addObject:textField]; - // If there are other fields in the inputs array, get the previous field and set the - // return key type on that to next. + // If there are other fields in the inputs array, set the previous field return key to Next if (_inputs.count > 1) { NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; @@ -627,12 +653,11 @@ - (void)addCustomTextField:(UITextField *)textField - (BOOL)textFieldShouldReturn:(UITextField *)textField { // If this is the last object in the inputs array, resign first responder - // as the form is at the end. if (textField == _inputs.lastObject) { [textField resignFirstResponder]; } - else // Otherwise find the next field and make it first responder. + else // Otherwise find the next field and make it first responder { NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; UITextField *nextField = _inputs[indexOfCurrentField + 1]; @@ -641,28 +666,79 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField return NO; } +#pragma mark - Keyboard + - (void)keyboardWillShow:(NSNotification *)notification { if(_keyboardIsVisible) return; + + NSDictionary *userInfo = notification.userInfo; + NSTimeInterval animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + UIViewAnimationOptions animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; + + // Get the keyboard frame in screen coordinates + CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; + + // Convert contentView frame to screen coordinates + UIWindow *window = self.view.window; + if (!window) { + window = _usingNewWindow ? _SCLAlertWindow : [SCLAlertView scl_currentKeyWindow]; + } - [UIView animateWithDuration:0.2f animations:^{ - CGRect f = self.view.frame; - f.origin.y -= KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; - self.view.frame = f; - }]; - _keyboardIsVisible = YES; + CGRect contentViewScreenFrame = [_contentView.superview convertRect:_contentView.frame toView:nil]; + CGFloat contentViewBottom = CGRectGetMaxY(contentViewScreenFrame); + CGFloat keyboardTop = CGRectGetMinY(keyboardFrameEnd); + + // Calculate how much the content view overlaps with the keyboard + CGFloat overlap = contentViewBottom - keyboardTop; + + // Add some padding so the content isn't flush against the keyboard + CGFloat padding = 10.0f; + + if (overlap > 0) { + _keyboardIsVisible = YES; + _tmpContentViewFrameOrigin = _contentView.frame.origin; + _tmpCircleViewFrameOrigin = _circleViewBackground.frame.origin; + + CGFloat offsetY = overlap + padding; + + [UIView animateWithDuration:animationDuration delay:0 options:animationCurve animations:^{ + CGRect contentFrame = self.contentView.frame; + contentFrame.origin.y -= offsetY; + self.contentView.frame = contentFrame; + + CGRect circleFrame = self.circleViewBackground.frame; + circleFrame.origin.y -= offsetY; + self.circleViewBackground.frame = circleFrame; + } completion:nil]; + } } - (void)keyboardWillHide:(NSNotification *)notification { - if(!_keyboardIsVisible) return; - - [UIView animateWithDuration:0.2f animations:^{ - CGRect f = self.view.frame; - f.origin.y += KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; - self.view.frame = f; - }]; - _keyboardIsVisible = NO; + if(_keyboardIsVisible) { + NSDictionary *userInfo = notification.userInfo; + NSTimeInterval animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + UIViewAnimationOptions animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; + + _keyboardIsVisible = NO; + + [UIView animateWithDuration:animationDuration delay:0 options:animationCurve animations:^{ + CGRect contentFrame = self.contentView.frame; + contentFrame.origin.y = self->_tmpContentViewFrameOrigin.y; + self.contentView.frame = contentFrame; + + CGRect circleFrame = self.circleViewBackground.frame; + circleFrame.origin.y = self->_tmpCircleViewFrameOrigin.y; + self.circleViewBackground.frame = circleFrame; + } completion:^(BOOL finished) { + // Only reset if keyboard hasn't been shown again during the animation + if (!self->_keyboardIsVisible) { + self->_tmpContentViewFrameOrigin = CGPointZero; + self->_tmpCircleViewFrameOrigin = CGPointZero; + } + }]; + } } #pragma mark - Buttons @@ -747,11 +823,10 @@ - (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selec - (void)buttonTapped:(SCLButton *)btn { - // Cancel Countdown timer + // Cancel countdown timer [buttonTimer cancelTimer]; - // If the button has a validation block, and the validation block returns NO, validation - // failed, so we should bail. + // Validate if needed if (btn.validationBlock && !btn.validationBlock()) { return; } @@ -781,15 +856,20 @@ - (void)buttonTapped:(SCLButton *)btn - (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse { + if (_buttons.count == 0) { + buttonTimer = nil; + return; + } + buttonIndex = MAX(buttonIndex, 0); - buttonIndex = MIN(buttonIndex, [_buttons count]); + buttonIndex = MIN(buttonIndex, (NSInteger)_buttons.count - 1); buttonTimer = [[SCLTimerDisplay alloc] initWithOrigin:CGPointMake(5, 5) radius:13 lineWidth:4]; buttonTimer.buttonIndex = buttonIndex; buttonTimer.reverse = reverse; } -#pragma mark - Show Alert +#pragma mark - Show Alert (Core) - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle duration:(NSTimeInterval)duration completeText:(NSString *)completeText style:(SCLAlertViewStyle)style { @@ -870,7 +950,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima break; } - // Custom Alert color + // Custom alert color override if(_customViewColor) { viewColor = _customViewColor; @@ -880,11 +960,9 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima if ([title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { self.labelTitle.text = title; - // Adjust text view size, if necessary + // Adjust text view size if necessary CGSize sz = CGSizeMake(_windowWidth - 24.0f, CGFLOAT_MAX); - CGSize size = [_labelTitle sizeThatFits:sz]; - CGFloat ht = ceilf(size.height); if (ht > _titleHeight) { self.windowHeight += (ht - _titleHeight); @@ -892,18 +970,15 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima self.subTitleY += 20; } } else { - // Title is nil, we can move the body message to center and remove it from superView + // No title: center body and remove title view self.windowHeight -= _labelTitle.frame.size.height; [_labelTitle removeFromSuperview]; _labelTitle = nil; - _subTitleY = kCircleHeight - 20; } // Subtitle if ([subTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { - - // No custom text if (_attributedFormatBlock == nil) { _viewText.text = subTitle; } else { @@ -911,11 +986,9 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima _viewText.attributedText = self.attributedFormatBlock(subTitle); } - // Adjust text view size, if necessary + // Adjust text view size if necessary CGSize sz = CGSizeMake(_windowWidth - 24.0f, CGFLOAT_MAX); - CGSize size = [_viewText sizeThatFits:sz]; - CGFloat ht = ceilf(size.height); if (ht < _subTitleHeight) { self.windowHeight -= (_subTitleHeight - ht); @@ -925,7 +998,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima self.subTitleHeight = ht; } } else { - // Subtitle is nil, we can move the title to center and remove it from superView + // No subtitle: center title and remove body view self.subTitleHeight = 0.0f; self.windowHeight -= _viewText.frame.size.height; [_viewText removeFromSuperview]; @@ -939,7 +1012,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima self.windowHeight -= kTitleTop; } - // Add button, if necessary + // Add button if needed if(completeText != nil) { [self addDoneButtonWithTitle:completeText]; @@ -987,17 +1060,19 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima } } - // Adding duration + // Duration if (duration > 0) { [durationTimer invalidate]; if (buttonTimer && _buttons.count > 0) { - SCLButton *btn = _buttons[buttonTimer.buttonIndex]; + NSInteger buttonIndex = MIN(MAX(buttonTimer.buttonIndex, 0), (NSInteger)_buttons.count - 1); + SCLButton *btn = _buttons[buttonIndex]; btn.timer = buttonTimer; + __weak __typeof(self) weakSelf = self; [buttonTimer startTimerWithTimeLimit:duration completed:^{ - [self buttonTapped:btn]; + [weakSelf buttonTapped:btn]; }]; } else @@ -1018,7 +1093,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima // Show the alert view [self showView]; - // Chainable objects + // Chainable responder return [[SCLAlertViewResponder alloc] init:self]; } @@ -1075,7 +1150,6 @@ - (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NS [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleQuestion]; } - #pragma mark - Show using new window - (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration @@ -1147,11 +1221,13 @@ - (void)alertIsDismissed:(SCLDismissBlock)dismissBlock self.dismissBlock = dismissBlock; } -- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock{ +- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock +{ self.dismissAnimationCompletionBlock = dismissAnimationCompletionBlock; } -- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock{ +- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock +{ self.showAnimationCompletionBlock = showAnimationCompletionBlock; } @@ -1168,7 +1244,7 @@ - (SCLForceHideBlock)forceHideBlock:(SCLForceHideBlock)forceHideBlock - (CGRect)mainScreenFrame { - return [self isAppExtension] ? _extensionBounds : [UIApplication sharedApplication].keyWindow.bounds; + return [self isAppExtension] ? _extensionBounds : [SCLAlertView scl_currentKeyWindow].bounds; } - (BOOL)isAppExtension @@ -1188,15 +1264,29 @@ - (void)makeShadowBackground - (void)makeBlurBackground { - UIView *appView = (_usingNewWindow) ? [UIApplication sharedApplication].keyWindow.subviews.lastObject : _rootViewController.view; - UIImage *image = [UIImage convertViewToImage:appView]; - UIImage *blurSnapshotImage = [image applyBlurWithRadius:5.0f - tintColor:[UIColor colorWithWhite:0.2f - alpha:0.7f] - saturationDeltaFactor:1.8f - maskImage:nil]; + UIView *fallbackView = _rootViewController.view; + UIView *appView = _usingNewWindow ? (UIView *)[SCLAlertView scl_currentKeyWindow] : fallbackView; + + // Final fallback in case it still comes as nil + if (!appView) { + appView = [SCLAlertView scl_resolveAppViewWithFallback:fallbackView]; + } - _backgroundView.image = blurSnapshotImage; + [appView layoutIfNeeded]; + + UIImage *snapshot = [UIImage convertViewToImage:appView]; + if (snapshot) { + UIImage *blurSnapshotImage = [snapshot applyBlurWithRadius:5.0f + tintColor:[UIColor colorWithWhite:0.2f + alpha:0.7f] + saturationDeltaFactor:1.8f + maskImage:nil]; + + _backgroundView.image = blurSnapshotImage; + } else { + _backgroundView.image = nil; + _backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4f]; + } _backgroundView.alpha = 0.0f; _backgroundOpacity = 1.0f; } @@ -1227,7 +1317,7 @@ - (void)setBackground } } -#pragma mark - Show Alert +#pragma mark - Show Alert (Animations) - (void)showView { @@ -1267,7 +1357,7 @@ - (void)showView } } -#pragma mark - Hide Alert +#pragma mark - Hide Alert (Animations) - (void)hideView { @@ -1323,7 +1413,7 @@ - (void)hideView if (_usingNewWindow) { - // Restore previous window + // Restore the previous key window after hiding the alert [self.previousWindow makeKeyAndVisible]; self.previousWindow = nil; } @@ -1353,12 +1443,12 @@ - (void)fadeOutWithDuration:(NSTimeInterval)duration [self.view removeFromSuperview]; [self removeFromParentViewController]; - if (_usingNewWindow) { - // Remove current window + if (self.usingNewWindow) { + // Remove current alert window [self.SCLAlertWindow setHidden:YES]; self.SCLAlertWindow = nil; } - if ( _dismissAnimationCompletionBlock ){ + if ( self.dismissAnimationCompletionBlock ){ self.dismissAnimationCompletionBlock(); } }]; @@ -1434,7 +1524,7 @@ - (void)slideOutFromCenter - (void)simplyDisappear { - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; self.view.alpha = 1.0f; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ @@ -1442,7 +1532,6 @@ - (void)simplyDisappear }); } - #pragma mark - Show Animations - (void)fadeIn @@ -1454,11 +1543,11 @@ - (void)fadeIn delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; self.view.alpha = 1.0f; } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }]; @@ -1466,66 +1555,38 @@ - (void)fadeIn - (void)slideInFromTop { - if (SYSTEM_VERSION_LESS_THAN(@"7.0")) - { - //From Frame - CGRect frame = self.backgroundView.frame; - frame.origin.y = -self.backgroundView.frame.size.height; - self.view.frame = frame; + // From frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = -self.backgroundView.frame.size.height; + self.view.frame = frame; + + [UIView animateWithDuration:0.5f delay:0.0f usingSpringWithDamping:0.6f initialSpringVelocity:0.5f options:0 animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; - [UIView animateWithDuration:0.3f animations:^{ - self.backgroundView.alpha = _backgroundOpacity; - - //To Frame - CGRect frame = self.backgroundView.frame; - frame.origin.y = 0.0f; - self.view.frame = frame; - - self.view.alpha = 1.0f; - } completion:^(BOOL completed) { - [UIView animateWithDuration:0.2f animations:^{ - self.view.center = _backgroundView.center; - } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ - self.showAnimationCompletionBlock(); - } - }]; - }]; - } - else { - //From Frame + // To frame CGRect frame = self.backgroundView.frame; - frame.origin.y = -self.backgroundView.frame.size.height; + frame.origin.y = 0.0f; self.view.frame = frame; - [UIView animateWithDuration:0.5f delay:0.0f usingSpringWithDamping:0.6f initialSpringVelocity:0.5f options:0 animations:^{ - self.backgroundView.alpha = _backgroundOpacity; - - //To Frame - CGRect frame = self.backgroundView.frame; - frame.origin.y = 0.0f; - self.view.frame = frame; - - self.view.alpha = 1.0f; - } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ - self.showAnimationCompletionBlock(); - } - }]; - } + self.view.alpha = 1.0f; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; } - (void)slideInFromBottom { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.y = self.backgroundView.frame.size.height; self.view.frame = frame; [UIView animateWithDuration:0.3f animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.y = 0.0f; self.view.frame = frame; @@ -1533,9 +1594,9 @@ - (void)slideInFromBottom self.view.alpha = 1.0f; } completion:^(BOOL completed) { [UIView animateWithDuration:0.2f animations:^{ - self.view.center = _backgroundView.center; + self.view.center = self.backgroundView.center; } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }]; @@ -1544,15 +1605,15 @@ - (void)slideInFromBottom - (void)slideInFromLeft { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.x = -self.backgroundView.frame.size.width; self.view.frame = frame; [UIView animateWithDuration:0.3f animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.x = 0.0f; self.view.frame = frame; @@ -1560,9 +1621,9 @@ - (void)slideInFromLeft self.view.alpha = 1.0f; } completion:^(BOOL completed) { [UIView animateWithDuration:0.2f animations:^{ - self.view.center = _backgroundView.center; + self.view.center = self.backgroundView.center; } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }]; @@ -1571,15 +1632,15 @@ - (void)slideInFromLeft - (void)slideInFromRight { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.x = self.backgroundView.frame.size.width; self.view.frame = frame; [UIView animateWithDuration:0.3f animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.x = 0.0f; self.view.frame = frame; @@ -1587,9 +1648,9 @@ - (void)slideInFromRight self.view.alpha = 1.0f; } completion:^(BOOL completed) { [UIView animateWithDuration:0.2f animations:^{ - self.view.center = _backgroundView.center; + self.view.center = self.backgroundView.center; } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }]; @@ -1598,23 +1659,23 @@ - (void)slideInFromRight - (void)slideInFromCenter { - //From Frame + // From frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(3.0f, 3.0f)); self.view.alpha = 0.0f; [UIView animateWithDuration:0.3f animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(1.0f, 1.0f)); self.view.alpha = 1.0f; } completion:^(BOOL completed) { [UIView animateWithDuration:0.2f animations:^{ - self.view.center = _backgroundView.center; + self.view.center = self.backgroundView.center; } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }]; @@ -1623,23 +1684,23 @@ - (void)slideInFromCenter - (void)slideInToCenter { - //From Frame + // From frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(0.1f, 0.1f)); self.view.alpha = 0.0f; [UIView animateWithDuration:0.3f animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(1.0f, 1.0f)); self.view.alpha = 1.0f; } completion:^(BOOL completed) { [UIView animateWithDuration:0.2f animations:^{ - self.view.center = _backgroundView.center; + self.view.center = self.backgroundView.center; } completion:^(BOOL finished) { - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }]; @@ -1652,38 +1713,50 @@ - (void)simplyAppear self.view.alpha = 0.0f; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; self.view.alpha = 1.0f; - if ( _showAnimationCompletionBlock ){ + if ( self.showAnimationCompletionBlock ){ self.showAnimationCompletionBlock(); } }); } +@end +@implementation SCLAlertViewBuilder__WithFluent +- (instancetype)init { + if (self = [super init]) { + [self setupFluent]; + } + return self; +} +- (void)setupFluent {} @end @interface SCLALertViewTextFieldBuilder() #pragma mark - Parameters @property(copy, nonatomic) NSString *parameterTitle; +@property(copy, nonatomic) NSString *parameterDefaultText; #pragma mark - Available later after adding @property(weak, nonatomic) SCLTextView *textField; #pragma mark - Setters @property(copy, nonatomic) SCLALertViewTextFieldBuilder *(^title) (NSString *title); +@property(copy, nonatomic) SCLALertViewTextFieldBuilder *(^defaultText) (NSString *defaultText); @end @implementation SCLALertViewTextFieldBuilder -- (SCLALertViewTextFieldBuilder *(^) (NSString *title))title { - if (!_title) { - __weak typeof(self) weakSelf = self; - _title = ^(NSString *title){ - weakSelf.parameterTitle = title; - return weakSelf; - }; - } - return _title; +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.title = ^(NSString *title){ + weakSelf.parameterTitle = title; + return weakSelf; + }; + self.defaultText = ^(NSString *defaultText){ + weakSelf.parameterDefaultText = defaultText; + return weakSelf; + }; } @end @@ -1691,6 +1764,7 @@ @interface SCLALertViewButtonBuilder() #pragma mark - Parameters @property(copy, nonatomic) NSString *parameterTitle; +@property(copy, nonatomic) NSString *parameterDefaultText; @property(weak, nonatomic) id parameterTarget; @property(assign, nonatomic) SEL parameterSelector; @property(copy, nonatomic) void(^parameterActionBlock)(void); @@ -1701,6 +1775,7 @@ @interface SCLALertViewButtonBuilder() #pragma mark - Setters @property(copy, nonatomic) SCLALertViewButtonBuilder *(^title) (NSString *title); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^defaultText) (NSString *defaultText); @property(copy, nonatomic) SCLALertViewButtonBuilder *(^target) (id target); @property(copy, nonatomic) SCLALertViewButtonBuilder *(^selector) (SEL selector); @property(copy, nonatomic) SCLALertViewButtonBuilder *(^actionBlock) (void(^actionBlock)(void)); @@ -1709,56 +1784,34 @@ @interface SCLALertViewButtonBuilder() @end @implementation SCLALertViewButtonBuilder -- (SCLALertViewButtonBuilder *(^) (NSString *title))title { - if (!_title) { - __weak typeof(self) weakSelf = self; - _title = ^(NSString *title){ - weakSelf.parameterTitle = title; - return weakSelf; - }; - } - return _title; -} -- (SCLALertViewButtonBuilder *(^) (id target))target { - if (!_target) { - __weak typeof(self) weakSelf = self; - _target = ^(id target){ - weakSelf.parameterTarget = target; - return weakSelf; - }; - } - return _target; -} -- (SCLALertViewButtonBuilder *(^) (SEL selector))selector { - if (!_selector) { - __weak typeof(self) weakSelf = self; - _selector = ^(SEL selector){ - weakSelf.parameterSelector = selector; - return weakSelf; - }; - } - return _selector; -} -- (SCLALertViewButtonBuilder *(^) (void(^actionBlock)(void)))actionBlock { - if (!_actionBlock) { - __weak typeof(self) weakSelf = self; - _actionBlock = ^(void(^actionBlock)(void)){ - weakSelf.parameterActionBlock = actionBlock; - return weakSelf; - }; - } - return _actionBlock; -} -- (SCLALertViewButtonBuilder *(^) (BOOL(^validationBlock)(void)))validationBlock { - if (!_validationBlock) { - __weak typeof(self) weakSelf = self; - _validationBlock = ^(BOOL(^validationBlock)(void)){ - weakSelf.parameterValidationBlock = validationBlock; - return weakSelf; - }; - } - return _validationBlock; +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.title = ^(NSString *title){ + weakSelf.parameterTitle = title; + return weakSelf; + }; + self.defaultText = ^(NSString *defaultText){ + weakSelf.parameterDefaultText = defaultText; + return weakSelf; + }; + self.target = ^(id target){ + weakSelf.parameterTarget = target; + return weakSelf; + }; + self.selector = ^(SEL selector){ + weakSelf.parameterSelector = selector; + return weakSelf; + }; + self.actionBlock = ^(void(^actionBlock)(void)){ + weakSelf.parameterActionBlock = actionBlock; + return weakSelf; + }; + self.validationBlock = ^(BOOL(^validationBlock)(void)){ + weakSelf.parameterValidationBlock = validationBlock; + return weakSelf; + }; } + @end @@ -1770,6 +1823,178 @@ @interface SCLAlertViewBuilder() @implementation SCLAlertViewBuilder +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.cornerRadius = ^(CGFloat cornerRadius) { + weakSelf.alertView.cornerRadius = cornerRadius; + return weakSelf; + }; + self.tintTopCircle = ^(BOOL tintTopCircle) { + weakSelf.alertView.tintTopCircle = tintTopCircle; + return weakSelf; + }; + self.useLargerIcon = ^(BOOL useLargerIcon) { + weakSelf.alertView.useLargerIcon = useLargerIcon; + return weakSelf; + }; + self.labelTitle = ^(UILabel *labelTitle) { + weakSelf.alertView.labelTitle = labelTitle; + return weakSelf; + }; + self.viewText = ^(UITextView *viewText) { + weakSelf.alertView.viewText = viewText; + return weakSelf; + }; + self.activityIndicatorView = ^(UIActivityIndicatorView *activityIndicatorView) { + weakSelf.alertView.activityIndicatorView = activityIndicatorView; + return weakSelf; + }; + self.shouldDismissOnTapOutside = ^(BOOL shouldDismissOnTapOutside) { + weakSelf.alertView.shouldDismissOnTapOutside = shouldDismissOnTapOutside; + return weakSelf; + }; + self.soundURL = ^(NSURL *soundURL) { + weakSelf.alertView.soundURL = soundURL; + return weakSelf; + }; + self.attributedFormatBlock = ^(SCLAttributedFormatBlock attributedFormatBlock) { + weakSelf.alertView.attributedFormatBlock = attributedFormatBlock; + return weakSelf; + }; + self.completeButtonFormatBlock = ^(CompleteButtonFormatBlock completeButtonFormatBlock) { + weakSelf.alertView.completeButtonFormatBlock = completeButtonFormatBlock; + return weakSelf; + }; + self.buttonFormatBlock = ^(ButtonFormatBlock buttonFormatBlock) { + weakSelf.alertView.buttonFormatBlock = buttonFormatBlock; + return weakSelf; + }; + self.forceHideBlock = ^(SCLForceHideBlock forceHideBlock) { + weakSelf.alertView.forceHideBlock = forceHideBlock; + return weakSelf; + }; + self.hideAnimationType = ^(SCLAlertViewHideAnimation hideAnimationType) { + weakSelf.alertView.hideAnimationType = hideAnimationType; + return weakSelf; + }; + self.showAnimationType = ^(SCLAlertViewShowAnimation showAnimationType) { + weakSelf.alertView.showAnimationType = showAnimationType; + return weakSelf; + }; + self.backgroundType = ^(SCLAlertViewBackground backgroundType) { + weakSelf.alertView.backgroundType = backgroundType; + return weakSelf; + }; + self.customViewColor = ^(UIColor *customViewColor) { + weakSelf.alertView.customViewColor = customViewColor; + return weakSelf; + }; + self.backgroundViewColor = ^(UIColor *backgroundViewColor) { + weakSelf.alertView.backgroundViewColor = backgroundViewColor; + return weakSelf; + }; + self.iconTintColor = ^(UIColor *iconTintColor) { + weakSelf.alertView.iconTintColor = iconTintColor; + return weakSelf; + }; + self.circleIconHeight = ^(CGFloat circleIconHeight) { + weakSelf.alertView.circleIconHeight = circleIconHeight; + return weakSelf; + }; + self.extensionBounds = ^(CGRect extensionBounds) { + weakSelf.alertView.extensionBounds = extensionBounds; + return weakSelf; + }; + self.statusBarHidden = ^(BOOL statusBarHidden) { + weakSelf.alertView.statusBarHidden = statusBarHidden; + return weakSelf; + }; + self.statusBarStyle = ^(UIStatusBarStyle statusBarStyle) { + weakSelf.alertView.statusBarStyle = statusBarStyle; + return weakSelf; + }; + self.alertIsDismissed = ^(SCLDismissBlock dismissBlock) { + [weakSelf.alertView alertIsDismissed:dismissBlock]; + return weakSelf; + }; + self.alertDismissAnimationIsCompleted = ^(SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock) { + [weakSelf.alertView alertDismissAnimationIsCompleted:dismissAnimationCompletionBlock]; + return weakSelf; + }; + self.alertShowAnimationIsCompleted = ^(SCLShowAnimationCompletionBlock showAnimationCompletionBlock) { + [weakSelf.alertView alertShowAnimationIsCompleted:showAnimationCompletionBlock]; + return weakSelf; + }; + self.removeTopCircle = ^(void) { + [weakSelf.alertView removeTopCircle]; + return weakSelf; + }; + self.addCustomView = ^(UIView *view) { + [weakSelf.alertView addCustomView:view]; + return weakSelf; + }; + self.addTextField = ^(NSString *title, NSString *defaultText) { + [weakSelf.alertView addTextField:title setDefaultText:defaultText]; + return weakSelf; + }; + self.addCustomTextField = ^(UITextField *textField) { + [weakSelf.alertView addCustomTextField:textField]; + return weakSelf; + }; + self.addSwitchViewWithLabelTitle = ^(NSString *title) { + [weakSelf.alertView addSwitchViewWithLabel:title]; + return weakSelf; + }; + self.addTimerToButtonIndex = ^(NSInteger buttonIndex, BOOL reverse) { + [weakSelf.alertView addTimerToButtonIndex:buttonIndex reverse:reverse]; + return weakSelf; + }; + self.setTitleFontFamily = ^(NSString *titleFontFamily, CGFloat size) { + [weakSelf.alertView setTitleFontFamily:titleFontFamily withSize:size]; + return weakSelf; + }; + self.setBodyTextFontFamily = ^(NSString *bodyTextFontFamily, CGFloat size) { + [weakSelf.alertView setBodyTextFontFamily:bodyTextFontFamily withSize:size]; + return weakSelf; + }; + self.setButtonsTextFontFamily = ^(NSString *buttonsFontFamily, CGFloat size) { + [weakSelf.alertView setButtonsTextFontFamily:buttonsFontFamily withSize:size]; + return weakSelf; + }; + self.addButtonWithActionBlock = ^(NSString *title, SCLActionBlock action) { + [weakSelf.alertView addButton:title actionBlock:action]; + return weakSelf; + }; + self.addButtonWithValidationBlock = ^(NSString *title, SCLValidationBlock validationBlock, SCLActionBlock action) { + [weakSelf.alertView addButton:title validationBlock:validationBlock actionBlock:action]; + return weakSelf; + }; + self.addButtonWithTarget = ^(NSString *title, id target, SEL selector) { + [weakSelf.alertView addButton:title target:target selector:selector]; + return weakSelf; + }; + + self.addButtonWithBuilder = ^(SCLALertViewButtonBuilder *builder){ + SCLButton *button = nil; + if (builder.parameterTarget && builder.parameterSelector) { + button = [weakSelf.alertView addButton:builder.parameterTitle target:builder.parameterTarget selector:builder.parameterSelector]; + } + else if (builder.parameterValidationBlock && builder.parameterActionBlock) { + button = [weakSelf.alertView addButton:builder.parameterTitle validationBlock:builder.parameterValidationBlock actionBlock:builder.parameterActionBlock]; + } + else if (builder.parameterActionBlock) { + button = [weakSelf.alertView addButton:builder.parameterTitle actionBlock:builder.parameterActionBlock]; + } + builder.button = button; + return weakSelf; + }; + + self.addTextFieldWithBuilder = ^(SCLALertViewTextFieldBuilder *builder){ + builder.textField = [weakSelf.alertView addTextField:builder.parameterTitle setDefaultText:builder.parameterDefaultText]; + return weakSelf; + }; +} + #pragma mark - Init - (instancetype)init { @@ -1794,413 +2019,6 @@ - (instancetype)initWithNewWindowWidth:(CGFloat)width { } return self; } - -#pragma mark - Properties -- (SCLAlertViewBuilder *(^) (CGFloat cornerRadius))cornerRadius { - if (!_cornerRadius) { - __weak typeof(self) weakSelf = self; - _cornerRadius = ^(CGFloat cornerRadius) { - weakSelf.alertView.cornerRadius = cornerRadius; - return weakSelf; - }; - } - return _cornerRadius; -} - -- (SCLAlertViewBuilder *(^) (BOOL tintTopCircle))tintTopCircle { - if (!_tintTopCircle) { - __weak typeof(self) weakSelf = self; - _tintTopCircle = ^(BOOL tintTopCircle) { - weakSelf.alertView.tintTopCircle = tintTopCircle; - return weakSelf; - }; - } - return _tintTopCircle; -} -- (SCLAlertViewBuilder *(^) (BOOL useLargerIcon))useLargerIcon { - if (!_useLargerIcon) { - __weak typeof(self) weakSelf = self; - _useLargerIcon = ^(BOOL useLargerIcon) { - weakSelf.alertView.useLargerIcon = useLargerIcon; - return weakSelf; - }; - } - return _useLargerIcon; -} -- (SCLAlertViewBuilder *(^) (UILabel *labelTitle))labelTitle { - if (!_labelTitle) { - __weak typeof(self) weakSelf = self; - _labelTitle = ^(UILabel *labelTitle) { - weakSelf.alertView.labelTitle = labelTitle; - return weakSelf; - }; - } - return _labelTitle; -} -- (SCLAlertViewBuilder *(^) (UITextView *viewText))viewText { - if (!_viewText) { - __weak typeof(self) weakSelf = self; - _viewText = ^(UITextView *viewText) { - weakSelf.alertView.viewText = viewText; - return weakSelf; - }; - } - return _viewText; -} -- (SCLAlertViewBuilder *(^) (UIActivityIndicatorView *activityIndicatorView))activityIndicatorView { - if (!_activityIndicatorView) { - __weak typeof(self) weakSelf = self; - _activityIndicatorView = ^(UIActivityIndicatorView *activityIndicatorView) { - weakSelf.alertView.activityIndicatorView = activityIndicatorView; - return weakSelf; - }; - } - return _activityIndicatorView; -} -- (SCLAlertViewBuilder *(^) (BOOL shouldDismissOnTapOutside))shouldDismissOnTapOutside { - if (!_shouldDismissOnTapOutside) { - __weak typeof(self) weakSelf = self; - _shouldDismissOnTapOutside = ^(BOOL shouldDismissOnTapOutside) { - weakSelf.alertView.shouldDismissOnTapOutside = shouldDismissOnTapOutside; - return weakSelf; - }; - } - return _shouldDismissOnTapOutside; -} -- (SCLAlertViewBuilder *(^) (NSURL *soundURL))soundURL { - if (!_soundURL) { - __weak typeof(self) weakSelf = self; - _soundURL = ^(NSURL *soundURL) { - weakSelf.alertView.soundURL = soundURL; - return weakSelf; - }; - } - return _soundURL; -} -- (SCLAlertViewBuilder *(^) (SCLAttributedFormatBlock attributedFormatBlock))attributedFormatBlock { - if (!_attributedFormatBlock) { - __weak typeof(self) weakSelf = self; - _attributedFormatBlock = ^(SCLAttributedFormatBlock attributedFormatBlock) { - weakSelf.alertView.attributedFormatBlock = attributedFormatBlock; - return weakSelf; - }; - } - return _attributedFormatBlock; -} -- (SCLAlertViewBuilder *(^) (CompleteButtonFormatBlock completeButtonFormatBlock))completeButtonFormatBlock { - if (!_completeButtonFormatBlock) { - __weak typeof(self) weakSelf = self; - _completeButtonFormatBlock = ^(CompleteButtonFormatBlock completeButtonFormatBlock) { - weakSelf.alertView.completeButtonFormatBlock = completeButtonFormatBlock; - return weakSelf; - }; - } - return _completeButtonFormatBlock; -} -- (SCLAlertViewBuilder *(^) (ButtonFormatBlock buttonFormatBlock))buttonFormatBlock { - if (!_buttonFormatBlock) { - __weak typeof(self) weakSelf = self; - _buttonFormatBlock = ^(ButtonFormatBlock buttonFormatBlock) { - weakSelf.alertView.buttonFormatBlock = buttonFormatBlock; - return weakSelf; - }; - } - return _buttonFormatBlock; -} -- (SCLAlertViewBuilder *(^) (SCLForceHideBlock forceHideBlock))forceHideBlock { - if (!_forceHideBlock) { - __weak typeof(self) weakSelf = self; - _forceHideBlock = ^(SCLForceHideBlock forceHideBlock) { - weakSelf.alertView.forceHideBlock = forceHideBlock; - return weakSelf; - }; - } - return _forceHideBlock; -} -- (SCLAlertViewBuilder *(^) (SCLAlertViewHideAnimation hideAnimationType))hideAnimationType { - if (!_hideAnimationType) { - __weak typeof(self) weakSelf = self; - _hideAnimationType = ^(SCLAlertViewHideAnimation hideAnimationType) { - weakSelf.alertView.hideAnimationType = hideAnimationType; - return weakSelf; - }; - } - return _hideAnimationType; -} -- (SCLAlertViewBuilder *(^) (SCLAlertViewShowAnimation showAnimationType))showAnimationType { - if (!_showAnimationType) { - __weak typeof(self) weakSelf = self; - _showAnimationType = ^(SCLAlertViewShowAnimation showAnimationType) { - weakSelf.alertView.showAnimationType = showAnimationType; - return weakSelf; - }; - } - return _showAnimationType; -} -- (SCLAlertViewBuilder *(^) (SCLAlertViewBackground backgroundType))backgroundType { - if (!_backgroundType) { - __weak typeof(self) weakSelf = self; - _backgroundType = ^(SCLAlertViewBackground backgroundType) { - weakSelf.alertView.backgroundType = backgroundType; - return weakSelf; - }; - } - return _backgroundType; -} -- (SCLAlertViewBuilder *(^) (UIColor *customViewColor))customViewColor { - if (!_customViewColor) { - __weak typeof(self) weakSelf = self; - _customViewColor = ^(UIColor *customViewColor) { - weakSelf.alertView.customViewColor = customViewColor; - return weakSelf; - }; - } - return _customViewColor; -} -- (SCLAlertViewBuilder *(^) (UIColor *backgroundViewColor))backgroundViewColor { - if (!_backgroundViewColor) { - __weak typeof(self) weakSelf = self; - _backgroundViewColor = ^(UIColor *backgroundViewColor) { - weakSelf.alertView.backgroundViewColor = backgroundViewColor; - return weakSelf; - }; - } - return _backgroundViewColor; -} -- (SCLAlertViewBuilder *(^) (UIColor *iconTintColor))iconTintColor { - if (!_iconTintColor) { - __weak typeof(self) weakSelf = self; - _iconTintColor = ^(UIColor *iconTintColor) { - weakSelf.alertView.iconTintColor = iconTintColor; - return weakSelf; - }; - } - return _iconTintColor; -} -- (SCLAlertViewBuilder *(^) (CGFloat circleIconHeight))circleIconHeight { - if (!_circleIconHeight) { - __weak typeof(self) weakSelf = self; - _circleIconHeight = ^(CGFloat circleIconHeight) { - weakSelf.alertView.circleIconHeight = circleIconHeight; - return weakSelf; - }; - } - return _circleIconHeight; -} -- (SCLAlertViewBuilder *(^) (CGRect extensionBounds))extensionBounds { - if (!_extensionBounds) { - __weak typeof(self) weakSelf = self; - _extensionBounds = ^(CGRect extensionBounds) { - weakSelf.alertView.extensionBounds = extensionBounds; - return weakSelf; - }; - } - return _extensionBounds; -} -- (SCLAlertViewBuilder *(^) (BOOL statusBarHidden))statusBarHidden { - if (!_statusBarHidden) { - __weak typeof(self) weakSelf = self; - _statusBarHidden = ^(BOOL statusBarHidden) { - weakSelf.alertView.statusBarHidden = statusBarHidden; - return weakSelf; - }; - } - return _statusBarHidden; -} -- (SCLAlertViewBuilder *(^) (UIStatusBarStyle statusBarStyle))statusBarStyle { - if (!_statusBarStyle) { - __weak typeof(self) weakSelf = self; - _statusBarStyle = ^(UIStatusBarStyle statusBarStyle) { - weakSelf.alertView.statusBarStyle = statusBarStyle; - return weakSelf; - }; - } - return _statusBarStyle; -} - -#pragma mark - Custom Setters -- (SCLAlertViewBuilder *(^) (SCLDismissBlock dismissBlock))alertIsDismissed { - if (!_alertIsDismissed) { - __weak typeof(self) weakSelf = self; - _alertIsDismissed = ^(SCLDismissBlock dismissBlock) { - [weakSelf.alertView alertIsDismissed:dismissBlock]; - return weakSelf; - }; - } - return _alertIsDismissed; -} --(SCLAlertViewBuilder *(^)(SCLDismissAnimationCompletionBlock))alertDismissAnimationIsCompleted{ - if (!_alertDismissAnimationIsCompleted) { - __weak typeof(self) weakSelf = self; - _alertDismissAnimationIsCompleted = ^(SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock) { - [weakSelf.alertView alertDismissAnimationIsCompleted:dismissAnimationCompletionBlock]; - return weakSelf; - }; - } - return _alertDismissAnimationIsCompleted; -} --(SCLAlertViewBuilder *(^)(SCLShowAnimationCompletionBlock))alertShowAnimationIsCompleted{ - if (!_alertShowAnimationIsCompleted) { - __weak typeof(self) weakSelf = self; - _alertShowAnimationIsCompleted = ^(SCLShowAnimationCompletionBlock showAnimationCompletionBlock) { - [weakSelf.alertView alertShowAnimationIsCompleted:showAnimationCompletionBlock]; - return weakSelf; - }; - } - return _alertShowAnimationIsCompleted; -} -- (SCLAlertViewBuilder *(^) (void))removeTopCircle { - if (!_removeTopCircle) { - __weak typeof(self) weakSelf = self; - _removeTopCircle = ^(void) { - [weakSelf.alertView removeTopCircle]; - return weakSelf; - }; - } - return _removeTopCircle; -} -- (SCLAlertViewBuilder *(^) (UIView *view))addCustomView { - if (!_addCustomView) { - __weak typeof(self) weakSelf = self; - _addCustomView = ^(UIView *view) { - [weakSelf.alertView addCustomView:view]; - return weakSelf; - }; - } - return _addCustomView; -} -- (SCLAlertViewBuilder *(^) (NSString *title))addTextField { - if (!_addTextField) { - __weak typeof(self) weakSelf = self; - _addTextField = ^(NSString *title) { - [weakSelf.alertView addTextField:title]; - return weakSelf; - }; - } - return _addTextField; -} -- (SCLAlertViewBuilder *(^) (UITextField *textField))addCustomTextField { - if (!_addCustomTextField) { - __weak typeof(self) weakSelf = self; - _addCustomTextField = ^(UITextField *textField) { - [weakSelf.alertView addCustomTextField:textField]; - return weakSelf; - }; - } - return _addCustomTextField; -} -- (SCLAlertViewBuilder *(^) (NSString *title))addSwitchViewWithLabelTitle { - if (!_addSwitchViewWithLabelTitle) { - __weak typeof(self) weakSelf = self; - _addSwitchViewWithLabelTitle = ^(NSString *title) { - [weakSelf.alertView addSwitchViewWithLabel:title]; - return weakSelf; - }; - } - return _addSwitchViewWithLabelTitle; -} -- (SCLAlertViewBuilder *(^) (NSInteger buttonIndex, BOOL reverse))addTimerToButtonIndex { - if (!_addTimerToButtonIndex) { - __weak typeof(self) weakSelf = self; - _addTimerToButtonIndex = ^(NSInteger buttonIndex, BOOL reverse) { - [weakSelf.alertView addTimerToButtonIndex:buttonIndex reverse:reverse]; - return weakSelf; - }; - } - return _addTimerToButtonIndex; -} -- (SCLAlertViewBuilder *(^) (NSString *titleFontFamily, CGFloat size))setTitleFontFamily { - if (!_setTitleFontFamily) { - __weak typeof(self) weakSelf = self; - _setTitleFontFamily = ^(NSString *titleFontFamily, CGFloat size) { - [weakSelf.alertView setTitleFontFamily:titleFontFamily withSize:size]; - return weakSelf; - }; - } - return _setTitleFontFamily; -} -- (SCLAlertViewBuilder *(^) (NSString *bodyTextFontFamily, CGFloat size))setBodyTextFontFamily { - if (!_setBodyTextFontFamily) { - __weak typeof(self) weakSelf = self; - _setBodyTextFontFamily = ^(NSString *bodyTextFontFamily, CGFloat size) { - [weakSelf.alertView setBodyTextFontFamily:bodyTextFontFamily withSize:size]; - return weakSelf; - }; - } - return _setBodyTextFontFamily; -} -- (SCLAlertViewBuilder *(^) (NSString *buttonsFontFamily, CGFloat size))setButtonsTextFontFamily { - if (!_setButtonsTextFontFamily) { - __weak typeof(self) weakSelf = self; - _setButtonsTextFontFamily = ^(NSString *buttonsFontFamily, CGFloat size) { - [weakSelf.alertView setButtonsTextFontFamily:buttonsFontFamily withSize:size]; - return weakSelf; - }; - } - return _setButtonsTextFontFamily; -} -- (SCLAlertViewBuilder *(^) (NSString *title, SCLActionBlock action))addButtonWithActionBlock { - if (!_addButtonWithActionBlock) { - __weak typeof(self) weakSelf = self; - _addButtonWithActionBlock = ^(NSString *title, SCLActionBlock action) { - [weakSelf.alertView addButton:title actionBlock:action]; - return weakSelf; - }; - } - return _addButtonWithActionBlock; -} -- (SCLAlertViewBuilder *(^) (NSString *title, SCLValidationBlock validationBlock, SCLActionBlock action))addButtonWithValidationBlock { - if (!_addButtonWithValidationBlock) { - __weak typeof(self) weakSelf = self; - _addButtonWithValidationBlock = ^(NSString *title, SCLValidationBlock validationBlock, SCLActionBlock action) { - [weakSelf.alertView addButton:title validationBlock:validationBlock actionBlock:action]; - return weakSelf; - }; - } - return _addButtonWithValidationBlock; -} -- (SCLAlertViewBuilder *(^) (NSString *title, id target, SEL selector))addButtonWithTarget { - if (!_addButtonWithTarget) { - __weak typeof(self) weakSelf = self; - _addButtonWithTarget = ^(NSString *title, id target, SEL selector) { - [weakSelf.alertView addButton:title target:target selector:selector]; - return weakSelf; - }; - } - return _addButtonWithTarget; -} - -#pragma mark - Builders -- (SCLAlertViewBuilder *(^)(SCLALertViewButtonBuilder *builder))addButtonWithBuilder { - if (!_addButtonWithBuilder) { - __weak typeof(self) weakSelf = self; - _addButtonWithBuilder = ^(SCLALertViewButtonBuilder *builder){ - SCLButton *button = nil; - if (builder.parameterTarget && builder.parameterSelector) { - button = [weakSelf.alertView addButton:builder.parameterTitle target:builder.parameterTarget selector:builder.parameterSelector]; - } - else if (builder.parameterValidationBlock && builder.parameterActionBlock) { - button = [weakSelf.alertView addButton:builder.parameterTitle validationBlock:builder.parameterValidationBlock actionBlock:builder.parameterActionBlock]; - } - else if (builder.parameterActionBlock) { - button = [weakSelf.alertView addButton:builder.parameterTitle actionBlock:builder.parameterActionBlock]; - } - builder.button = button; - return weakSelf; - }; - } - return _addButtonWithBuilder; -} -- (SCLAlertViewBuilder *(^)(SCLALertViewTextFieldBuilder *builder))addTextFieldWithBuilder { - if (!_addTextFieldWithBuilder) { - __weak typeof(self) weakSelf = self; - _addTextFieldWithBuilder = ^(SCLALertViewTextFieldBuilder *builder){ - builder.textField = [weakSelf.alertView addTextField:builder.parameterTitle]; - return weakSelf; - }; - } - return _addTextFieldWithBuilder; -} @end @interface SCLAlertViewShowBuilder() @@ -2209,6 +2027,7 @@ @interface SCLAlertViewShowBuilder() @property(copy, nonatomic) UIImage *parameterImage; @property(copy, nonatomic) UIColor *parameterColor; @property(copy, nonatomic) NSString *parameterTitle; +@property(copy, nonatomic) NSString *parameterDefaultText; @property(copy, nonatomic) NSString *parameterSubTitle; @property(copy, nonatomic) NSString *parameterCompleteText; @property(copy, nonatomic) NSString *parameterCloseButtonTitle; @@ -2232,99 +2051,50 @@ @interface SCLAlertViewShowBuilder() @implementation SCLAlertViewShowBuilder +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.viewController = ^(UIViewController *viewController){ + weakSelf.parameterViewController = viewController; + return weakSelf; + }; + self.image = ^(UIImage *image) { + weakSelf.parameterImage = image; + return weakSelf; + }; + self.color = ^(UIColor *color) { + weakSelf.parameterColor = color; + return weakSelf; + }; + self.title = ^(NSString *title){ + weakSelf.parameterTitle = title; + return weakSelf; + }; + self.subTitle = ^(NSString *subTitle){ + weakSelf.parameterSubTitle = subTitle; + return weakSelf; + }; + self.completeText = ^(NSString *completeText){ + weakSelf.parameterCompleteText = completeText; + return weakSelf; + }; + self.style = ^(SCLAlertViewStyle style){ + weakSelf.parameterStyle = style; + return weakSelf; + }; + self.closeButtonTitle = ^(NSString *closeButtonTitle){ + weakSelf.parameterCloseButtonTitle = closeButtonTitle; + return weakSelf; + }; + self.duration = ^(NSTimeInterval duration){ + weakSelf.parameterDuration = duration; + return weakSelf; + }; + self.show = ^(SCLAlertView *view, UIViewController *controller) { + [weakSelf showAlertView:view onViewController:controller]; + }; +} #pragma mark - Setters -- (SCLAlertViewShowBuilder *(^)(UIViewController *viewController))viewController { - if (!_viewController) { - __weak typeof(self) weakSelf = self; - _viewController = ^(UIViewController *viewController){ - weakSelf.parameterViewController = viewController; - return weakSelf; - }; - } - return _viewController; -} -- (SCLAlertViewShowBuilder *(^)(UIImage *image))image { - if (!_image) { - __weak typeof(self) weakSelf = self; - _image = ^(UIImage *image) { - weakSelf.parameterImage = image; - return weakSelf; - }; - } - return _image; -} -- (SCLAlertViewShowBuilder *(^)(UIColor *color))color { - if (!_color) { - __weak typeof(self) weakSelf = self; - _color = ^(UIColor *color) { - weakSelf.parameterColor = color; - return weakSelf; - }; - } - return _color; -} -- (SCLAlertViewShowBuilder *(^)(NSString *title))title { - if (!_title) { - __weak typeof(self) weakSelf = self; - _title = ^(NSString *title){ - weakSelf.parameterTitle = title; - return weakSelf; - }; - } - return _title; -} -- (SCLAlertViewShowBuilder *(^)(NSString *subTitle))subTitle { - if (!_subTitle) { - __weak typeof(self) weakSelf = self; - _subTitle = ^(NSString *subTitle){ - weakSelf.parameterSubTitle = subTitle; - return weakSelf; - }; - } - return _subTitle; -} -- (SCLAlertViewShowBuilder *(^)(NSString *completeText))completeText { - if (!_completeText) { - __weak typeof(self) weakSelf = self; - _completeText = ^(NSString *completeText){ - weakSelf.parameterCompleteText = completeText; - return weakSelf; - }; - } - return _completeText; -} - -- (SCLAlertViewShowBuilder *(^)(SCLAlertViewStyle style))style { - if (!_style) { - __weak typeof(self) weakSelf = self; - _style = ^(SCLAlertViewStyle style){ - weakSelf.parameterStyle = style; - return weakSelf; - }; - } - return _style; -} -- (SCLAlertViewShowBuilder *(^)(NSString *closeButtonTitle))closeButtonTitle { - if (!_closeButtonTitle) { - __weak typeof(self) weakSelf = self; - _closeButtonTitle = ^(NSString *closeButtonTitle){ - weakSelf.parameterCloseButtonTitle = closeButtonTitle; - return weakSelf; - }; - } - return _closeButtonTitle; -} -- (SCLAlertViewShowBuilder *(^)(NSTimeInterval duration))duration { - if (!_duration) { - __weak typeof(self) weakSelf = self; - _duration = ^(NSTimeInterval duration){ - weakSelf.parameterDuration = duration; - return weakSelf; - }; - } - return _duration; -} - (void)showAlertView:(SCLAlertView *)alertView { [self showAlertView:alertView onViewController:self.parameterViewController]; @@ -2341,14 +2111,4 @@ - (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewControll } } -- (void (^)(SCLAlertView *view, UIViewController *controller))show { - if (!_show) { - __weak typeof(self) weakSelf = self; - _show = ^(SCLAlertView *view, UIViewController *controller) { - [weakSelf showAlertView:view onViewController:controller]; - }; - } - return _show; -} - @end diff --git a/SCLAlertView/SCLAlertViewResponder.h b/SCLAlertView/SCLAlertViewResponder.h index 0dfb77b..148a1fc 100644 --- a/SCLAlertView/SCLAlertViewResponder.h +++ b/SCLAlertView/SCLAlertViewResponder.h @@ -6,25 +6,21 @@ // Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import Foundation; -#else #import -#endif #import "SCLAlertView.h" @interface SCLAlertViewResponder : NSObject -/** TODO - * - * TODO - */ +/// Initializes the responder associated with an instance of SCLAlertView. - (instancetype)init:(SCLAlertView *)alertview; -/** TODO - * - * TODO - */ +/// Updates the alert's title. +- (void)setTitle:(NSString *)title; + +/// Updates the alert's subtitle / body text. +- (void)setSubTitle:(NSString *)subTitle; + +/// Closes the alert. - (void)close; @end diff --git a/SCLAlertView/SCLAlertViewResponder.m b/SCLAlertView/SCLAlertViewResponder.m index 847ed9d..2318c53 100644 --- a/SCLAlertView/SCLAlertViewResponder.m +++ b/SCLAlertView/SCLAlertViewResponder.m @@ -10,33 +10,36 @@ @interface SCLAlertViewResponder () -@property SCLAlertView *alertview; +// Weak reference to the alert to avoid retain cycles. Valid while the alert is alive. +@property (weak, nonatomic) SCLAlertView *alertview; @end @implementation SCLAlertViewResponder -// -//// Allow alerts to be closed/renamed in a chainable manner -//// Example: SCLAlertView().showSuccess(self, title: "Test", subTitle: "Value").close() - -// Initialisation and Title/Subtitle/Close functions +// Binds the responder to a presented alert, enabling title/subtitle updates and dismissal. - (instancetype)init:(SCLAlertView *)alertview { - self.alertview = alertview; + self = [super init]; + if (self) { + self.alertview = alertview; + } return self; } -- (void)setTitletitle:(NSString *)title +// Updates the alert title (useful for async state changes). +- (void)setTitle:(NSString *)title { self.alertview.labelTitle.text = title; } +// Updates the alert subtitle/body text. - (void)setSubTitle:(NSString *)subTitle { self.alertview.viewText.text = subTitle; } +// Dismisses the alert using its configured animation. - (void)close { [self.alertview hideView]; diff --git a/SCLAlertView/SCLAlertViewStyleKit.m b/SCLAlertView/SCLAlertViewStyleKit.m index f467f47..45b982e 100644 --- a/SCLAlertView/SCLAlertViewStyleKit.m +++ b/SCLAlertView/SCLAlertViewStyleKit.m @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // #import "SCLAlertViewStyleKit.h" @@ -28,14 +28,14 @@ @implementation SCLAlertViewStyleKit + (void)initialize { - // Do something + // Reserved for future initialization. } #pragma mark - Drawing Methods + (void)drawCheckmark { - // Checkmark Shape Drawing + // Checkmark shape drawing UIBezierPath *checkmarkShapePath = [[UIBezierPath alloc] init]; [checkmarkShapePath moveToPoint:CGPointMake(73.25, 14.05)]; [checkmarkShapePath addCurveToPoint:CGPointMake(64.51, 13.86) controlPoint1: CGPointMake(70.98, 11.44) controlPoint2: CGPointMake(66.78, 11.26)]; @@ -57,7 +57,7 @@ + (void)drawCheckmark + (void)drawCross { - // Cross Shape Drawing + // Cross shape drawing UIBezierPath *crossShapePath = [[UIBezierPath alloc] init]; [crossShapePath moveToPoint:CGPointMake(10, 70)]; [crossShapePath addLineToPoint:CGPointMake(70, 10)]; @@ -74,7 +74,7 @@ + (void)drawCross + (void)drawNotice { - // Notice Shape Drawing + // Notice shape drawing UIBezierPath *noticeShapePath = [[UIBezierPath alloc] init]; [noticeShapePath moveToPoint:CGPointMake(72, 48.54)]; [noticeShapePath addLineToPoint:CGPointMake(72, 39.9)]; @@ -112,11 +112,11 @@ + (void)drawNotice + (void)drawWarning { - // Color Declarations + // Color declarations UIColor *greyColor = [UIColor colorWithRed:0.236 green:0.236 blue:0.236 alpha:1.000]; - // Warning Group - // Warning Circle Drawing + // Warning group + // Warning circle drawing UIBezierPath *warningCirclePath = [[UIBezierPath alloc] init]; [warningCirclePath moveToPoint:CGPointMake(40.94, 63.39)]; [warningCirclePath addCurveToPoint:CGPointMake(36.03, 65.55) controlPoint1: CGPointMake(39.06, 63.39) controlPoint2: CGPointMake(37.36, 64.18)]; @@ -134,7 +134,7 @@ + (void)drawWarning [warningCirclePath fill]; - //// Warning Shape Drawing + // Warning shape drawing UIBezierPath *warningShapePath = [[UIBezierPath alloc] init]; [warningShapePath moveToPoint:CGPointMake(46.23, 4.26)]; [warningShapePath addCurveToPoint:CGPointMake(40.94, 2.5) controlPoint1: CGPointMake(44.91, 3.09) controlPoint2: CGPointMake(43.02, 2.5)]; @@ -156,10 +156,10 @@ + (void)drawWarning + (void)drawInfo { - // Color Declarations + // Color declarations UIColor *color0 = [UIColor colorWithRed:1.000 green:1.000 blue:1.000 alpha:1.000]; - // Info Shape Drawing + // Info shape drawing UIBezierPath *infoShapePath = [[UIBezierPath alloc] init]; [infoShapePath moveToPoint:CGPointMake(45.66, 15.96)]; [infoShapePath addCurveToPoint:CGPointMake(45.66, 5.22) controlPoint1: CGPointMake(48.78, 12.99) controlPoint2: CGPointMake(48.78, 8.19)]; @@ -185,10 +185,10 @@ + (void)drawInfo + (void)drawEdit { - // Color Declarations + // Color declarations UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; - // Edit shape Drawing + // Edit shape drawing UIBezierPath *editPathPath = [[UIBezierPath alloc] init]; [editPathPath moveToPoint:CGPointMake(71, 2.7)]; [editPathPath addCurveToPoint:CGPointMake(71.9, 15.2) controlPoint1:CGPointMake(74.7, 5.9) controlPoint2:CGPointMake(75.1, 11.6)]; @@ -238,10 +238,10 @@ + (void)drawEdit + (void)drawQuestion { - // Color Declarations + // Color declarations UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; - // Questionmark Shape Drawing + // Question mark shape drawing UIBezierPath *questionShapePath = [[UIBezierPath alloc] init]; [questionShapePath moveToPoint: CGPointMake(33.75, 54.1)]; [questionShapePath addLineToPoint: CGPointMake(44.15, 54.1)]; diff --git a/SCLAlertView/SCLButton.h b/SCLAlertView/SCLButton.h index a1fb3a5..33ebf92 100755 --- a/SCLAlertView/SCLButton.h +++ b/SCLAlertView/SCLButton.h @@ -3,14 +3,12 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif + +NS_ASSUME_NONNULL_BEGIN @class SCLTimerDisplay; @@ -18,8 +16,8 @@ typedef void (^SCLActionBlock)(void); typedef BOOL (^SCLValidationBlock)(void); -typedef NSDictionary* (^CompleteButtonFormatBlock)(void); -typedef NSDictionary* (^ButtonFormatBlock)(void); +typedef NSDictionary * _Nonnull (^CompleteButtonFormatBlock)(void); +typedef NSDictionary * _Nonnull (^ButtonFormatBlock)(void); // Action Types typedef NS_ENUM(NSInteger, SCLActionType) @@ -29,81 +27,109 @@ typedef NS_ENUM(NSInteger, SCLActionType) SCLBlock }; -/** Set button action type. - * - * Holds the button action type. +/** + Button action type. + + Indicates how the button should handle taps (selector-based or block-based). */ @property SCLActionType actionType; -/** Set action button block. - * - * TODO +/** + Action block executed when the button is tapped. + + @note Used when actionType == SCLBlock. */ -@property (copy, nonatomic) SCLActionBlock actionBlock; +@property (copy, nonatomic, nullable) SCLActionBlock actionBlock; + +/** + Validation block executed before the action. + + Return YES to allow dismissal and call the action block; NO to keep the alert visible. -/** Set Validation button block. - * - * Set one kind of validation and keeps the alert visible until the validation is successful + @note If provided and returns NO, the action is not executed and the alert remains visible. */ -@property (copy, nonatomic) SCLValidationBlock validationBlock; +@property (copy, nonatomic, nullable) SCLValidationBlock validationBlock; -/** Set Complete button format block. - * - * Holds the complete button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor +/** + Complete button format block. + + Provides full button styling. + + Supported keys: + - backgroundColor (UIColor) + - borderWidth (NSNumber/CGFloat) + - borderColor (UIColor) + - textColor (UIColor) */ -@property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; +@property (copy, nonatomic, nullable) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** + Button format block. + + Provides button styling. -/** Set button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor + Supported keys: + - backgroundColor (UIColor) + - borderWidth (NSNumber/CGFloat) + - borderColor (UIColor) + - textColor (UIColor) */ -@property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; +@property (copy, nonatomic, nullable) ButtonFormatBlock buttonFormatBlock; -/** Set SCLButton color. - * - * Set SCLButton color. +/** + Default background color for the button. + + @note UI_APPEARANCE_SELECTOR is supported. */ -@property (strong, nonatomic) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; +@property (strong, nonatomic, nullable) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; + +/** + Target for selector-based actions. -/** Set Target object. - * - * Target is an object that holds the information necessary to send a message to another object when an event occurs. + @note Used when actionType == SCLSelector. */ -@property id target; +@property (nullable) id target; + +/** + Selector to invoke on the target for selector-based actions. -/** Set selector id. - * - * A selector is the name used to select a method to execute for an object, - * or the unique identifier that replaces the name when the source code is compiled. + @note Used when actionType == SCLSelector. */ -@property SEL selector; +@property (nullable) SEL selector; -/** Parse button configuration - * - * Parse ButtonFormatBlock and CompleteButtonFormatBlock setting custom configuration. - * Set keys : backgroundColor, borderWidth, borderColor, textColor +/** + Applies configuration returned by a format block. + + @param buttonConfig The configuration dictionary. + @discussion Supported keys: backgroundColor, borderWidth, borderColor, textColor. */ - (void)parseConfig:(NSDictionary *)buttonConfig; -/** Set button timer. - * - * Holds the button timer, if present. +/** + Button timer (if present). + + Used to show countdown/progress on the button. */ -@property (strong, nonatomic) SCLTimerDisplay *timer; +@property (strong, nonatomic, nullable) SCLTimerDisplay *timer; -/** Init method - * +/** + Designated initializer for SCLButton. + + @param windowWidth The width of the alert window used to size the button. + @return An initialized SCLButton instance. */ - (instancetype)initWithWindowWidth:(CGFloat)windowWidth; -/** Adjust width of the button according to the width of the alert and - * the number of buttons. Only used when buttons are horizontally aligned. - * - * @param windowWidth The width of the alert. - * @param numberOfButtons The number of buttons in the alert. +/** + Adjusts the button width based on alert width and number of buttons. + + Only used when buttons are horizontally aligned. + + @param windowWidth The alert window width. + @param numberOfButtons Total number of buttons in the alert. */ - (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons; @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLButton.m b/SCLAlertView/SCLButton.m index 056ce0c..593b599 100755 --- a/SCLAlertView/SCLButton.m +++ b/SCLAlertView/SCLButton.m @@ -65,6 +65,11 @@ - (void)setupWithWindowWidth:(CGFloat)windowWidth - (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons { + if (numberOfButtons == 0) { + self.frame = CGRectMake(0.0f, 0.0f, MAX(windowWidth - (MARGIN_BUTTON * 2), 0.0f), MIN_HEIGHT); + return; + } + CGFloat allButtonsWidth = windowWidth - (MARGIN_BUTTON * 2); CGFloat buttonWidth = (allButtonsWidth - ((numberOfButtons - 1) * 10)) / numberOfButtons; @@ -103,7 +108,9 @@ - (void)setDefaultBackgroundColor:(UIColor *)defaultBackgroundColor - (void)setTimer:(SCLTimerDisplay *)timer { _timer = timer; - [self addSubview:timer]; + if (!timer.superview) { + [self addSubview:timer]; + } [timer updateFrame:self.frame.size]; timer.color = self.titleLabel.textColor; } @@ -145,23 +152,25 @@ - (void)parseConfig:(NSDictionary *)buttonConfig - (UIColor *)darkerColorForColor:(UIColor *)color { CGFloat r, g, b, a; - if ([color getRed:&r green:&g blue:&b alpha:&a]) + if ([color getRed:&r green:&g blue:&b alpha:&a]) { return [UIColor colorWithRed:MAX(r - 0.2f, 0.0f) green:MAX(g - 0.2f, 0.0f) blue:MAX(b - 0.2f, 0.0f) alpha:a]; - return nil; + } + return color; } - (UIColor *)lighterColorForColor:(UIColor *)color { CGFloat r, g, b, a; - if ([color getRed:&r green:&g blue:&b alpha:&a]) + if ([color getRed:&r green:&g blue:&b alpha:&a]) { return [UIColor colorWithRed:MIN(r + 0.2f, 1.0f) green:MIN(g + 0.2f, 1.0f) blue:MIN(b + 0.2f, 1.0f) alpha:a]; - return nil; + } + return color; } @end diff --git a/SCLAlertView/SCLMacros.h b/SCLAlertView/SCLMacros.h index 1fec837..5d6be5d 100644 --- a/SCLAlertView/SCLMacros.h +++ b/SCLAlertView/SCLMacros.h @@ -3,21 +3,28 @@ // SCLAlertView // // Created by Diogo Autilio on 10/03/15. -// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // #ifndef SCL_MACROS_H #define SCL_MACROS_H +// Create a UIColor from a 0xRRGGBB hex value (alpha is 1.0) #define UIColorFromHEX(rgbValue) [UIColor \ colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \ blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] +// Convert degrees to radians #define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180) + +// Timer granularity (seconds) used by internal animations/timers #define TIMER_STEP .01 + +// Starting angle offset (degrees) for circular drawings (e.g., timers) #define START_DEGREE_OFFSET -90 +// iOS version comparison helpers (string-based, e.g., @"14.0") #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) diff --git a/SCLAlertView/SCLSwitchView.h b/SCLAlertView/SCLSwitchView.h index ecc4d6c..469624b 100644 --- a/SCLAlertView/SCLSwitchView.h +++ b/SCLAlertView/SCLSwitchView.h @@ -3,21 +3,33 @@ // SCLAlertView // // Created by André Felipe Santos on 27/01/16. -// Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2016-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif +NS_ASSUME_NONNULL_BEGIN + +/** + A simple switch view with an optional label, configurable via UIAppearance. + */ @interface SCLSwitchView : UIView -@property (strong, nonatomic) UIColor *tintColor UI_APPEARANCE_SELECTOR; -@property (strong, nonatomic) UIColor *labelColor UI_APPEARANCE_SELECTOR; -@property (strong, nonatomic) UIFont *labelFont UI_APPEARANCE_SELECTOR; -@property (strong, nonatomic) NSString *labelText UI_APPEARANCE_SELECTOR; +/// Tint color for the switch (UIAppearance). +@property (strong, nonatomic, nullable) UIColor *tintColor UI_APPEARANCE_SELECTOR; + +/// Label color (UIAppearance). +@property (strong, nonatomic, nullable) UIColor *labelColor UI_APPEARANCE_SELECTOR; + +/// Label font (UIAppearance). +@property (strong, nonatomic, nullable) UIFont *labelFont UI_APPEARANCE_SELECTOR; + +/// Label text (UIAppearance). +@property (strong, nonatomic, nullable) NSString *labelText UI_APPEARANCE_SELECTOR; + +/// Selection state. @property (nonatomic, getter=isSelected) BOOL selected; @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLSwitchView.m b/SCLAlertView/SCLSwitchView.m index 93662ac..50addfc 100644 --- a/SCLAlertView/SCLSwitchView.m +++ b/SCLAlertView/SCLSwitchView.m @@ -9,6 +9,8 @@ #import "SCLSwitchView.h" #import "SCLMacros.h" +static const CGFloat kSpacing = 8.0f; + @interface SCLSwitchView () @property (strong, nonatomic) UISwitch *switchKnob; @@ -16,8 +18,6 @@ @interface SCLSwitchView () @end -#pragma mark - @implementation SCLSwitchView #pragma mark - Constructors @@ -56,38 +56,62 @@ - (instancetype)initWithFrame:(CGRect)frame - (void)setup { + self.backgroundColor = UIColor.clearColor; + // Add switch knob - self.switchKnob = [[UISwitch alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.f)]; + self.switchKnob = [[UISwitch alloc] initWithFrame:CGRectZero]; [self addSubview:self.switchKnob]; // Add switch label - CGFloat x, width, height; - x = self.switchKnob.frame.size.width + 8.0f; - width = self.frame.size.width - self.switchKnob.frame.size.width - 8.0f; - height = self.switchKnob.frame.size.height; - - self.switchLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, 0.0f, width, height)]; - - NSString *switchFontFamily = @"HelveticaNeue-Bold"; - CGFloat switchFontSize = 12.0f; - + self.switchLabel = [[UILabel alloc] initWithFrame:CGRectZero]; self.switchLabel.numberOfLines = 1; self.switchLabel.textAlignment = NSTextAlignmentLeft; self.switchLabel.lineBreakMode = NSLineBreakByTruncatingTail; self.switchLabel.adjustsFontSizeToFitWidth = YES; self.switchLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; self.switchLabel.minimumScaleFactor = 0.5f; - self.switchLabel.font = [UIFont fontWithName:switchFontFamily size:switchFontSize]; + self.switchLabel.font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:12.0f]; self.switchLabel.textColor = UIColorFromHEX(0x4D4D4D); [self addSubview:self.switchLabel]; } +#pragma mark - Layout + +- (CGSize)sizeThatFits:(CGSize)size { + CGSize switchSize = self.switchKnob.intrinsicContentSize; + CGFloat availableWidth = (size.width > 0 ? size.width : (switchSize.width + kSpacing + 120.0f)); // fallback width + CGFloat labelWidth = MAX(0, availableWidth - switchSize.width - kSpacing); + CGSize labelSize = [self.switchLabel sizeThatFits:CGSizeMake(labelWidth, CGFLOAT_MAX)]; + CGFloat height = MAX(labelSize.height, switchSize.height); + return CGSizeMake(availableWidth, height); +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGSize boundsSize = self.bounds.size; + CGSize switchSize = self.switchKnob.intrinsicContentSize; + + // Place switch at leading (x=0) + CGFloat switchX = 0.0f; + CGFloat switchY = (boundsSize.height - switchSize.height) / 2.0f; + self.switchKnob.frame = CGRectMake(switchX, switchY, switchSize.width, switchSize.height); + + // Label fills remaining space after switch + spacing + CGFloat labelX = CGRectGetMaxX(self.switchKnob.frame) + kSpacing; + CGFloat labelWidth = MAX(0, boundsSize.width - labelX); + CGSize labelFit = [self.switchLabel sizeThatFits:CGSizeMake(labelWidth, CGFLOAT_MAX)]; + CGFloat labelHeight = MIN(labelFit.height, boundsSize.height); + CGFloat labelY = (boundsSize.height - labelHeight) / 2.0f; + self.switchLabel.frame = CGRectMake(labelX, labelY, labelWidth, labelHeight); +} + #pragma mark - Getters - (UIColor *)tintColor { - return self.switchKnob.tintColor; + return self.switchKnob.onTintColor; } - (UIColor *)labelColor @@ -114,6 +138,7 @@ - (BOOL)isSelected - (void)setTintColor:(UIColor *)tintColor { + [super setTintColor:tintColor]; self.switchKnob.onTintColor = tintColor; } @@ -125,11 +150,13 @@ - (void)setLabelColor:(UIColor *)labelColor - (void)setLabelFont:(UIFont *)labelFont { self.switchLabel.font = labelFont; + [self setNeedsLayout]; } - (void)setLabelText:(NSString *)labelText { self.switchLabel.text = labelText; + [self setNeedsLayout]; } - (void)setSelected:(BOOL)selected diff --git a/SCLAlertView/SCLTextView.h b/SCLAlertView/SCLTextView.h index e691ef8..4cb4b65 100644 --- a/SCLAlertView/SCLTextView.h +++ b/SCLAlertView/SCLTextView.h @@ -3,15 +3,17 @@ // SCLAlertView // // Created by Diogo Autilio on 9/18/15. -// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif -@interface SCLTextView : UITextField +NS_ASSUME_NONNULL_BEGIN +/** + A UITextField subclass used by SCLAlertView for consistent styling and behavior. + */ +@interface SCLTextView : UITextField @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLTextView.m b/SCLAlertView/SCLTextView.m index c508359..8fa0271 100644 --- a/SCLAlertView/SCLTextView.m +++ b/SCLAlertView/SCLTextView.m @@ -8,49 +8,77 @@ #import "SCLTextView.h" -#define MIN_HEIGHT 30.0f +static const CGFloat kSCLTextViewHeight = 35.0f; +static const CGFloat kSCLTextViewHorizontalPadding = 8.0f; @implementation SCLTextView -- (instancetype)init -{ +- (instancetype)init { self = [super init]; - if (self) - { + if (self) { [self setup]; } return self; } -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if(self) - { +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { [self setup]; } return self; } -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) - { +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { [self setup]; } return self; } -- (void)setup -{ - self.frame = CGRectMake(0.0f, 0.0f, 0.0f, MIN_HEIGHT); - self.returnKeyType = UIReturnKeyDone; +- (void)setup { + self.backgroundColor = [UIColor whiteColor]; + self.textColor = [UIColor darkTextColor]; self.borderStyle = UITextBorderStyleRoundedRect; - self.autocapitalizationType = UITextAutocapitalizationTypeSentences; self.clearButtonMode = UITextFieldViewModeWhileEditing; - self.layer.masksToBounds = YES; - self.layer.borderWidth = 1.0f; + self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.autocorrectionType = UITextAutocorrectionTypeDefault; + self.autocapitalizationType = UITextAutocapitalizationTypeSentences; + self.returnKeyType = UIReturnKeyDone; + + // Internal padding via left/right views + UIView *leftPad = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCLTextViewHorizontalPadding, 1)]; + UIView *rightPad = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCLTextViewHorizontalPadding, 1)]; + self.leftView = leftPad; + self.leftViewMode = UITextFieldViewModeAlways; + self.rightView = rightPad; + self.rightViewMode = UITextFieldViewModeAlways; + + // Default minimum height + CGRect f = self.frame; + if (CGRectIsEmpty(f)) { + f = CGRectMake(0, 0, 0, kSCLTextViewHeight); + } else { + f.size.height = MAX(f.size.height, kSCLTextViewHeight); + } + self.frame = f; +} + +- (CGSize)intrinsicContentSize { + CGSize base = [super intrinsicContentSize]; + if (base.height <= 0) { + base.height = kSCLTextViewHeight; + } else { + base.height = MAX(base.height, kSCLTextViewHeight); + } + return base; +} + +- (CGSize)sizeThatFits:(CGSize)size { + CGSize fit = [super sizeThatFits:size]; + fit.height = MAX(fit.height, kSCLTextViewHeight); + return fit; } @end diff --git a/SCLAlertView/SCLTimerDisplay.h b/SCLAlertView/SCLTimerDisplay.h index 2f9bc18..0f90f60 100644 --- a/SCLAlertView/SCLTimerDisplay.h +++ b/SCLAlertView/SCLTimerDisplay.h @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Taylor Ryan on 8/18/15. -// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // // Taken from https://stackoverflow.com/questions/11783439/uibutton-with-timer @@ -22,18 +22,81 @@ CGFloat lineWidth; NSTimer *timer; SCLActionBlock completedBlock; + + // Precision/state + CFTimeInterval startTime; + CFTimeInterval pausedElapsed; + BOOL running; } +/// Current angle (in degrees or radians depending on implementation). @property CGFloat currentAngle; + +/// Index of the button this timer is attached to. @property NSInteger buttonIndex; + +/// Stroke color for the circular timer. @property (strong, nonatomic) UIColor *color; + +/// If YES, timer runs in reverse (countdown). @property (assign, nonatomic) BOOL reverse; +/** + Initializes a circular timer view. + + @param origin The origin point for the view. + @param r The radius of the circular timer. + @return An initialized SCLTimerDisplay instance. + */ - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r; + +/** + Initializes a circular timer view with custom line width. + + @param origin The origin point for the view. + @param r The radius of the circular timer. + @param width The stroke line width. + @return An initialized SCLTimerDisplay instance. + */ - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFloat)width; + +/** + Updates the frame/layout of the timer to fit a given size. + + @param size The new size to fit. + */ - (void)updateFrame:(CGSize)size; + +/** + Cancels and removes the timer, preventing completion from firing. + */ - (void)cancelTimer; + +/** + Stops the timer without removing the view. + */ - (void)stopTimer; + +/** + Starts the timer with a time limit. + + @param tl The time limit in seconds. + @param completed A block called when the timer completes. + */ - (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed; +/** + Pauses the timer. + + @note Kept for API compatibility; optional usage. + */ +- (void)pauseTimer; + +/** + Resumes the timer after a pause. + + @note Kept for API compatibility; optional usage. + */ +- (void)resumeTimer; + @end diff --git a/SCLAlertView/SCLTimerDisplay.m b/SCLAlertView/SCLTimerDisplay.m index 6921e81..47a99c2 100644 --- a/SCLAlertView/SCLTimerDisplay.m +++ b/SCLAlertView/SCLTimerDisplay.m @@ -11,6 +11,8 @@ @interface SCLTimerDisplay () +// Centered numeric readout for elapsed/remaining seconds. +// Kept as a subview to benefit from UILabel accessibility and text rendering. @property (strong, nonatomic) UILabel *countLabel; @end @@ -26,6 +28,9 @@ - (instancetype)initWithFrame:(CGRect)frame { self.backgroundColor = [UIColor clearColor]; currentAngle = 0.0f; + _color = [UIColor whiteColor]; + running = NO; + pausedElapsed = 0; } return self; } @@ -41,25 +46,50 @@ - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFl if (self) { self.backgroundColor = [UIColor clearColor]; currentAngle = START_DEGREE_OFFSET; + // Draw from the center of the stroke; subtract half line width from the radius to avoid clipping radius = r-(width/2); lineWidth = width; self.color = [UIColor whiteColor]; self.userInteractionEnabled = NO; - // Add count label + // Lightweight numeric HUD in the middle of the ring _countLabel = [[UILabel alloc] init]; _countLabel.textColor = [UIColor whiteColor]; _countLabel.backgroundColor = [UIColor clearColor]; _countLabel.font = [UIFont fontWithName: @"HelveticaNeue-Bold" size:12.0f]; _countLabel.textAlignment = NSTextAlignmentCenter; _countLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; + _countLabel.isAccessibilityElement = YES; + _countLabel.accessibilityTraits = UIAccessibilityTraitUpdatesFrequently; [self addSubview:_countLabel]; } return self; } +- (void)dealloc +{ + [self cancelTimer]; +} + +- (void)willMoveToSuperview:(UIView *)newSuperview +{ + if (newSuperview == nil) { + // Prevent orphaned timers when the view leaves the hierarchy + [self cancelTimer]; + } + [super willMoveToSuperview:newSuperview]; +} + +- (void)setColor:(UIColor *)color +{ + _color = color ?: [UIColor whiteColor]; + _countLabel.textColor = _color; + [self setNeedsDisplay]; +} + - (void)updateFrame:(CGSize)size { + // Position the ring in the trailing edge with a small inset; keep label centered CGFloat r = radius+(lineWidth/2); CGFloat originX = size.width - (2*r) - 5; @@ -71,6 +101,7 @@ - (void)updateFrame:(CGSize)size - (void)drawRect:(CGRect)rect { + // Draw progress ring from START_DEGREE_OFFSET to currentAngle UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius+(lineWidth/2), radius+(lineWidth/2)) radius:radius startAngle:DEGREES_TO_RADIANS(START_DEGREE_OFFSET) @@ -80,54 +111,126 @@ - (void)drawRect:(CGRect)rect aPath.lineWidth = lineWidth; [aPath stroke]; - _countLabel.text = [NSString stringWithFormat:@"%d", (int)currentTime]; + // Keep the numeric text aligned with the mode: + // - reverse: countdown shows remaining seconds + // - forward: count-up shows elapsed seconds + if (_reverse) { + int remaining = MAX((int)ceil(timerLimit - currentTime), 0); + _countLabel.text = [NSString stringWithFormat:@"%d", remaining]; + _countLabel.accessibilityLabel = [NSString stringWithFormat:@"%d seconds remaining", remaining]; + } else { + int elapsed = MIN((int)floor(currentTime), (int)ceil(timerLimit)); + _countLabel.text = [NSString stringWithFormat:@"%d", elapsed]; + _countLabel.accessibilityLabel = [NSString stringWithFormat:@"%d seconds elapsed", elapsed]; + } } - (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed { - if (_reverse) - { - currentTime = tl; - } - timerLimit = tl; - timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP target:self selector:@selector(updateTimerButton:) userInfo:nil repeats:YES]; - completedBlock = completed; + [self cancelTimer]; // Reset prior state and invalidate any running NSTimer + + timerLimit = MAX(0, tl); + // Use a single notion of time for simplicity: currentTime is "elapsed" regardless of mode + currentTime = 0.0; + currentAngle = START_DEGREE_OFFSET; + completedBlock = [completed copy]; _countLabel.textColor = _color; + + pausedElapsed = 0; + startTime = CACurrentMediaTime(); + running = YES; + + __weak typeof(self) weakSelf = self; + // Block-based NSTimer avoids needing a selector and reduces boilerplate; weakSelf prevents retain cycles + timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP repeats:YES block:^(NSTimer * _Nonnull t) { + [weakSelf updateTimerTick]; + }]; + // Common run loop modes keep the ring responsive while the UI is interacting (e.g., scrolling) + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + + [self setNeedsDisplay]; +} + +- (void)updateTimerTick +{ + if (!running) { return; } + + CFTimeInterval now = CACurrentMediaTime(); + CFTimeInterval elapsedSinceStart = now - startTime + pausedElapsed; + + // Clamp elapsed to the limit to stabilize the label at the end boundary + currentTime = MIN(elapsedSinceStart, timerLimit); + + if (_reverse) { + // Countdown visualization: arc shrinks from full circle to zero + CGFloat timeRemaining = MAX(timerLimit - elapsedSinceStart, 0.0); + CGFloat fractionRemaining = (timerLimit <= 0.0) ? 0.0 : (timeRemaining / timerLimit); + fractionRemaining = MIN(MAX(fractionRemaining, 0.0), 1.0); + // Map remaining fraction to end angle so the visible arc length is proportional to remaining time + currentAngle = (fractionRemaining * 360.0) + START_DEGREE_OFFSET; + } else { + // Count-up visualization: arc grows from zero to full circle + CGFloat fractionDone = (timerLimit <= 0.0) ? 1.0 : (elapsedSinceStart / timerLimit); + fractionDone = MIN(MAX(fractionDone, 0.0), 1.0); + currentAngle = (fractionDone * 360.0) + START_DEGREE_OFFSET; + } + + // Stop precisely at the limit to avoid overshooting due to timer granularity + BOOL finished = (elapsedSinceStart >= timerLimit); + if (finished) { + [self stopTimer]; + return; + } + [self setNeedsDisplay]; } - (void)cancelTimer { - [timer invalidate]; + running = NO; + if (timer) { + [timer invalidate]; + timer = nil; + } } - (void)stopTimer { - [timer invalidate]; + [self cancelTimer]; if (completedBlock != nil) { - completedBlock(); + // Copy to local before clearing to avoid re-entrancy surprises in user code + SCLActionBlock block = completedBlock; + completedBlock = nil; + block(); } } -- (void)updateTimerButton:(NSTimer *)timer +- (void)pauseTimer { - if (_reverse) - { - currentTime -= TIMER_STEP; - currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; - - if(currentTime <= 0) { - [self stopTimer]; - } + if (!running) return; + running = NO; + CFTimeInterval now = CACurrentMediaTime(); + // Accumulate elapsed time so resume continues from the correct point + pausedElapsed += (now - startTime); + if (timer) { + [timer setFireDate:[NSDate distantFuture]]; } - else { - currentTime += TIMER_STEP; - currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; +} - if(currentAngle >= (360 + START_DEGREE_OFFSET)) { - [self stopTimer]; - } +- (void)resumeTimer +{ + if (running || timerLimit <= 0) return; + running = YES; + // Restart time base; pausedElapsed carries the previous progress + startTime = CACurrentMediaTime(); + if (timer) { + [timer setFireDate:[NSDate date]]; + } else { + __weak typeof(self) weakSelf = self; + timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP repeats:YES block:^(NSTimer * _Nonnull t) { + [weakSelf updateTimerTick]; + }]; + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; } - [self setNeedsDisplay]; } @end diff --git a/SCLAlertView/UIImage+ImageEffects.m b/SCLAlertView/UIImage+ImageEffects.m index 280560e..7c27fbb 100755 --- a/SCLAlertView/UIImage+ImageEffects.m +++ b/SCLAlertView/UIImage+ImageEffects.m @@ -102,7 +102,7 @@ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #import #endif #import - +#import @implementation UIImage (ImageEffects) @@ -307,29 +307,41 @@ + (UIImage *)convertViewToImage return capturedScreen; } -+ (UIImage *)convertViewToImage:(UIView *)view -{ - CGFloat scale = [UIScreen mainScreen].scale; - UIImage *capturedScreen; - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) - { - //Optimized/fast method for rendering a UIView as image on iOS 7 and later versions. - UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, scale); - [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; - capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); ++ (UIImage *)convertViewToImage:(UIView *)view { + if (!view) { return nil; } + + [view layoutIfNeeded]; + + CGSize size = view.bounds.size; + if (size.width <= 0.0 || size.height <= 0.0) { + return nil; } - else - { - //For devices running on earlier iOS versions. - UIGraphicsBeginImageContextWithOptions(view.bounds.size,YES, scale); - [view.layer renderInContext:UIGraphicsGetCurrentContext()]; - capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); + + CGFloat scale = UIScreen.mainScreen.scale; + + if (@available(iOS 10.0, *)) { + UIGraphicsImageRendererFormat *fmt = [UIGraphicsImageRendererFormat defaultFormat]; + fmt.scale = scale; + fmt.opaque = YES; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:fmt]; + return [renderer imageWithActions:^(__kindof UIGraphicsImageRendererContext * _Nonnull context) { + BOOL ok = [view drawViewHierarchyInRect:(CGRect){.origin = CGPointZero, .size = size} + afterScreenUpdates:NO]; + if (!ok) { + [view.layer renderInContext:context.CGContext]; + } + }]; + } else { + UIGraphicsBeginImageContextWithOptions(size, YES, scale); + BOOL ok = [view drawViewHierarchyInRect:(CGRect){.origin = CGPointZero, .size = size} + afterScreenUpdates:NO]; + if (!ok) { + [view.layer renderInContext:UIGraphicsGetCurrentContext()]; + } + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); + return image; } - - return capturedScreen; } @end diff --git a/SCLAlertViewExample/AppDelegate.h b/SCLAlertViewExample/AppDelegate/AppDelegate.h similarity index 100% rename from SCLAlertViewExample/AppDelegate.h rename to SCLAlertViewExample/AppDelegate/AppDelegate.h diff --git a/SCLAlertViewExample/AppDelegate.m b/SCLAlertViewExample/AppDelegate/AppDelegate.m similarity index 100% rename from SCLAlertViewExample/AppDelegate.m rename to SCLAlertViewExample/AppDelegate/AppDelegate.m diff --git a/SCLAlertViewExample/Category/UIViewController+Alert.h b/SCLAlertViewExample/Category/UIViewController+Alert.h new file mode 100644 index 0000000..3a708fa --- /dev/null +++ b/SCLAlertViewExample/Category/UIViewController+Alert.h @@ -0,0 +1,22 @@ +// +// UIViewController+Alert.h +// SCLAlertView +// +// Created by Diogo Autilio on 31/10/20. +// Copyright © 2020 AnyKey Entertainment. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface UIViewController (Alert) + +typedef void (^ActionBlock)(void); + +- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message actionBlock:(nullable ActionBlock)actionBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertViewExample/Category/UIViewController+Alert.m b/SCLAlertViewExample/Category/UIViewController+Alert.m new file mode 100644 index 0000000..c56ddf9 --- /dev/null +++ b/SCLAlertViewExample/Category/UIViewController+Alert.m @@ -0,0 +1,34 @@ +// +// UIViewController+Alert.m +// SCLAlertView +// +// Created by Diogo Autilio on 31/10/20. +// Copyright © 2020-2025 AnyKey Entertainment. All rights reserved. +// + +#import "UIViewController+Alert.h" + +@implementation UIViewController (Alert) + +#pragma mark - Alerts + +- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message actionBlock:(nullable ActionBlock)actionBlock +{ + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + [alertController dismissViewControllerAnimated:YES completion:nil]; + if (actionBlock) { + actionBlock(); + } + }]; + [alertController addAction:okAction]; + + [self presentViewController:alertController animated:YES completion:nil]; +} + +@end diff --git a/SCLAlertViewExample/ViewController.h b/SCLAlertViewExample/ViewController/ViewController.h similarity index 100% rename from SCLAlertViewExample/ViewController.h rename to SCLAlertViewExample/ViewController/ViewController.h diff --git a/SCLAlertViewExample/ViewController.m b/SCLAlertViewExample/ViewController/ViewController.m similarity index 80% rename from SCLAlertViewExample/ViewController.m rename to SCLAlertViewExample/ViewController/ViewController.m index ebcc0af..d5811e6 100644 --- a/SCLAlertViewExample/ViewController.m +++ b/SCLAlertViewExample/ViewController/ViewController.m @@ -3,16 +3,17 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // #import "ViewController.h" #import "SCLAlertView.h" +#import "UIViewController+Alert.h" @interface ViewController () - @end +// MARK: Constants NSString *kSuccessTitle = @"Congratulations"; NSString *kErrorTitle = @"Connection error"; NSString *kNoticeTitle = @"Notice"; @@ -24,6 +25,8 @@ @interface ViewController () @implementation ViewController +#pragma mark - Success + - (IBAction)showSuccess:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; @@ -33,12 +36,10 @@ - (IBAction)showSuccess:(id)sender button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor whiteColor]; buttonConfig[@"textColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @2.0f; buttonConfig[@"borderColor"] = [UIColor greenColor]; - return buttonConfig; }; @@ -51,7 +52,8 @@ - (IBAction)showSuccess:(id)sender [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } -- (IBAction)showSuccessWithHorizontalButtons:(id)sender { +- (IBAction)showSuccessWithHorizontalButtons:(id)sender +{ SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; [alert setHorizontalButtons:YES]; @@ -60,12 +62,10 @@ - (IBAction)showSuccessWithHorizontalButtons:(id)sender { button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor whiteColor]; buttonConfig[@"textColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @2.0f; buttonConfig[@"borderColor"] = [UIColor greenColor]; - return buttonConfig; }; @@ -78,30 +78,42 @@ - (IBAction)showSuccessWithHorizontalButtons:(id)sender { [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Error + - (IBAction)showError:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showError:self title:@"An error with two title is presented ..." + [alert showError:self + title:@"An error with two title is presented ..." subTitle:@"You have not saved your Submission yet. Please save the Submission before accessing the Responses list. Blah de blah de blah, blah. Blah de blah de blah, blah.Blah de blah de blah, blah.Blah de blah de blah, blah.Blah de blah de blah, blah.Blah de blah de blah, End." - closeButtonTitle:@"OK" duration:0.0f]; + closeButtonTitle:@"OK" + duration:0.0f]; } +#pragma mark - Notice + - (IBAction)showNotice:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - alert.backgroundType = SCLAlertViewBackgroundBlur; - [alert showNotice:self title:kNoticeTitle subTitle:@"You've just displayed this awesome Pop Up View with blur effect" closeButtonTitle:kButtonTitle duration:0.0f]; + [alert showNotice:self + title:kNoticeTitle + subTitle:@"You've just displayed this awesome Pop Up View with blur effect" + closeButtonTitle:kButtonTitle + duration:0.0f]; } +#pragma mark - Warning + - (IBAction)showWarning:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showWarning:self title:kWarningTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Info + - (IBAction)showInfo:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -114,11 +126,13 @@ - (IBAction)showInfo:(id)sender [alert showInfo:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Edit + - (IBAction)showEdit:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - SCLTextView *textField = [alert addTextField:@"Enter your name"]; + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; [alert addButton:@"Show Name" actionBlock:^(void) { NSLog(@"Text value: %@", textField.text); }]; @@ -131,7 +145,7 @@ - (IBAction)showEditWithHorizontalButtons:(id)sender SCLAlertView *alert = [[SCLAlertView alloc] init]; [alert setHorizontalButtons:YES]; - SCLTextView *textField = [alert addTextField:@"Enter your name"]; + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; alert.hideAnimationType = SCLAlertViewHideAnimationSimplyDisappear; [alert addButton:@"Show Name" actionBlock:^(void) { NSLog(@"Text value: %@", textField.text); @@ -140,6 +154,8 @@ - (IBAction)showEditWithHorizontalButtons:(id)sender [alert showEdit:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Advanced + - (IBAction)showAdvanced:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -156,7 +172,7 @@ - (IBAction)showAdvanced:(id)sender NSLog(@"Second button tapped"); }]; - SCLTextView *textField = [alert addTextField:@"Enter your name"]; + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; [alert addButton:@"Show Name" actionBlock:^(void) { NSLog(@"Text value: %@", textField.text); @@ -165,18 +181,16 @@ - (IBAction)showAdvanced:(id)sender alert.completeButtonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor greenColor]; buttonConfig[@"borderColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @"1.0f"; buttonConfig[@"textColor"] = [UIColor blackColor]; - return buttonConfig; }; alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) { - NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc]initWithString:value]; + NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc] initWithString:value]; NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; @@ -210,7 +224,7 @@ - (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender NSLog(@"Second button tapped"); }]; - SCLTextView *textField = [alert addTextField:@"Enter your name"]; + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; [alert addButton:@"Show Name" actionBlock:^(void) { NSLog(@"Text value: %@", textField.text); @@ -219,18 +233,16 @@ - (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender alert.completeButtonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor greenColor]; buttonConfig[@"borderColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @"1.0f"; buttonConfig[@"textColor"] = [UIColor blackColor]; - return buttonConfig; }; alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) { - NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc]initWithString:value]; + NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc] initWithString:value]; NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; @@ -247,13 +259,16 @@ - (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender [alert showTitle:self title:@"Congratulations" subTitle:kAttributeTitle style:SCLAlertViewStyleSuccess closeButtonTitle:@"Done" duration:0.0f]; } +#pragma mark - Duration + - (IBAction)showWithDuration:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showNotice:self title:kNoticeTitle subTitle:@"You've just displayed this awesome Pop Up View with 5 seconds duration" closeButtonTitle:nil duration:5.0f]; } +#pragma mark - Custom + - (IBAction)showCustom:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -262,28 +277,34 @@ - (IBAction)showCustom:(id)sender [alert showCustom:self image:[UIImage imageNamed:@"git"] color:color title:@"Custom" subTitle:@"Add a custom icon and color for your own type of alert!" closeButtonTitle:@"OK" duration:0.0f]; } +#pragma mark - Validation + - (IBAction)showValidation:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - SCLTextView *evenField = [alert addTextField:@"Enter an even number"]; + SCLTextView *evenField = [alert addTextField:@"Enter an even number" setDefaultText:nil]; evenField.keyboardType = UIKeyboardTypeNumberPad; - SCLTextView *oddField = [alert addTextField:@"Enter an odd number"]; + SCLTextView *oddField = [alert addTextField:@"Enter an odd number" setDefaultText:nil]; oddField.keyboardType = UIKeyboardTypeNumberPad; - + + __weak __typeof(self) weakSelf = self; + [alert addButton:@"Test Validation" validationBlock:^BOOL{ if (evenField.text.length == 0) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"You forgot to add an even number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [evenField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; return NO; } if (oddField.text.length == 0) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"You forgot to add an odd number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [oddField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; return NO; } @@ -292,8 +313,9 @@ - (IBAction)showValidation:(id)sender if (!evenFieldPassedValidation) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"That is not an even number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [evenField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; return NO; } @@ -302,13 +324,14 @@ - (IBAction)showValidation:(id)sender if (!oddFieldPassedValidation) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"That is not an odd number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [oddField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; return NO; } return YES; } actionBlock:^{ - [[[UIAlertView alloc] initWithTitle:@"Great Job!" message:@"Thanks for playing." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; + [weakSelf showAlertWithTitle:@"Great Job!" message:@"Thanks for playing." actionBlock:nil]; }]; [alert showEdit:self title:@"Validation" subTitle:@"Ensure the data is correct before dismissing!" closeButtonTitle:@"Cancel" duration:0]; @@ -319,24 +342,28 @@ - (IBAction)showValidationWithHorizontalButtons:(id)sender SCLAlertView *alert = [[SCLAlertView alloc] init]; [alert setHorizontalButtons:YES]; - SCLTextView *evenField = [alert addTextField:@"Enter an even number"]; + SCLTextView *evenField = [alert addTextField:@"Enter an even number" setDefaultText:nil]; evenField.keyboardType = UIKeyboardTypeNumberPad; - SCLTextView *oddField = [alert addTextField:@"Enter an odd number"]; + SCLTextView *oddField = [alert addTextField:@"Enter an odd number" setDefaultText:nil]; oddField.keyboardType = UIKeyboardTypeNumberPad; + + __weak __typeof(self) weakSelf = self; [alert addButton:@"Test Validation" validationBlock:^BOOL{ if (evenField.text.length == 0) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"You forgot to add an even number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [evenField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; return NO; } if (oddField.text.length == 0) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"You forgot to add an odd number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [oddField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; return NO; } @@ -345,8 +372,9 @@ - (IBAction)showValidationWithHorizontalButtons:(id)sender if (!evenFieldPassedValidation) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"That is not an even number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [evenField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; return NO; } @@ -355,49 +383,61 @@ - (IBAction)showValidationWithHorizontalButtons:(id)sender if (!oddFieldPassedValidation) { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"That is not an odd number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [oddField becomeFirstResponder]; + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; return NO; } return YES; } actionBlock:^{ - [[[UIAlertView alloc] initWithTitle:@"Great Job!" message:@"Thanks for playing." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; + [weakSelf showAlertWithTitle:@"Great Job!" message:@"Thanks for playing." actionBlock:nil]; }]; [alert showEdit:self title:@"Validation" subTitle:@"Ensure the data is correct before dismissing!" closeButtonTitle:@"Cancel" duration:0]; } +#pragma mark - Waiting + - (IBAction)showWaiting:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - alert.showAnimationType = SCLAlertViewHideAnimationSlideOutToCenter; + alert.showAnimationType = SCLAlertViewShowAnimationSlideInToCenter; alert.hideAnimationType = SCLAlertViewHideAnimationSlideOutFromCenter; - alert.backgroundType = SCLAlertViewBackgroundTransparent; - [alert showWaiting:self title:@"Waiting..." - subTitle:@"You've just displayed this awesome Pop Up View with transparent background" - closeButtonTitle:nil duration:5.0f]; + [alert showWaiting:self + title:@"Waiting..." + subTitle:@"You've just displayed this awesome Pop Up View with transparent background" + closeButtonTitle:nil + duration:5.0f]; } +#pragma mark - Timer + - (IBAction)showTimer:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; [alert addTimerToButtonIndex:0 reverse:YES]; - [alert showInfo:self title:@"Countdown Timer" - subTitle:@"This alert has a duration set, and a countdown timer on the Dismiss button to show how long is left." - closeButtonTitle:@"Dismiss" duration:10.0f]; + [alert showInfo:self + title:@"Countdown Timer" + subTitle:@"This alert has a duration set, and a countdown timer on the Dismiss button to show how long is left." + closeButtonTitle:@"Dismiss" + duration:10.0f]; } +#pragma mark - Question + - (IBAction)showQuestion:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showQuestion:self title:@"Question?" subTitle:kSubtitle closeButtonTitle:@"Dismiss" duration:0.0f]; } -- (IBAction)showSwitch:(id)sender { +#pragma mark - Switch + +- (IBAction)showSwitch:(id)sender +{ SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; alert.tintTopCircle = NO; alert.iconTintColor = [UIColor brownColor]; @@ -408,38 +448,37 @@ - (IBAction)showSwitch:(id)sender { [[SCLSwitchView appearance] setTintColor:[UIColor brownColor]]; SCLButton *button = [alert addButton:@"Done" target:self selector:@selector(firstButton)]; - button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; buttonConfig[@"cornerRadius"] = @"17.5f"; - return buttonConfig; }; [alert showCustom:self image:[UIImage imageNamed:@"switch"] color:[UIColor brownColor] title:kInfoTitle subTitle:kSubtitle closeButtonTitle:nil duration:0.0f]; } +#pragma mark - Actions + - (void)firstButton { NSLog(@"First button tapped"); } +#pragma mark - Custom Button + - (IBAction)showWithButtonCustom:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; SCLButton *button = [alert addButton:@"First Button" target:self selector:@selector(firstButton)]; - button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor whiteColor]; buttonConfig[@"textColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @2.0f; buttonConfig[@"borderColor"] = [UIColor greenColor]; buttonConfig[@"font"] = [UIFont fontWithName:@"ComicSansMS" size:13]; - return buttonConfig; }; diff --git a/SCLAlertViewFramework/SCLAlertViewFramework.h b/SCLAlertViewFramework/SCLAlertViewFramework.h index 5981fc4..e4576ca 100644 --- a/SCLAlertViewFramework/SCLAlertViewFramework.h +++ b/SCLAlertViewFramework/SCLAlertViewFramework.h @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Eugene Tulusha on 9/13/16. -// Copyright © 2016 AnyKey Entertainment. All rights reserved. +// Copyright © 2016-2025 AnyKey Entertainment. All rights reserved. // @import Foundation; diff --git a/SCLAlertViewTests/SCLAlertViewBuilderTests.m b/SCLAlertViewTests/SCLAlertViewBuilderTests.m new file mode 100644 index 0000000..0516ac5 --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewBuilderTests.m @@ -0,0 +1,86 @@ +// +// SCLAlertViewBuilderTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" + +@interface SCLAlertViewBuilderTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewBuilderTests + +- (void)testBuilderAppliesPropertiesAndAddsContent +{ + SCLAlertViewBuilder *builder = [[SCLAlertViewBuilder alloc] init]; + builder.cornerRadius(9.0f) + .tintTopCircle(NO) + .statusBarHidden(YES) + .statusBarStyle(UIStatusBarStyleLightContent) + .addTextField(@"Name", @"Diogo") + .addSwitchViewWithLabelTitle(@"Enabled") + .addButtonWithActionBlock(@"OK", ^{ + }); + + XCTAssertEqualWithAccuracy(builder.alertView.cornerRadius, 9.0f, 0.001f); + XCTAssertFalse(builder.alertView.tintTopCircle); + XCTAssertTrue(builder.alertView.statusBarHidden); + XCTAssertEqual(builder.alertView.statusBarStyle, UIStatusBarStyleLightContent); + XCTAssertEqual([self buttonsInView:builder.alertView.view].count, 1U); +} + +- (void)testButtonBuilderCreatesButtonAndExposesIt +{ + SCLAlertViewBuilder *alertBuilder = [[SCLAlertViewBuilder alloc] init]; + SCLALertViewButtonBuilder *buttonBuilder = [[SCLALertViewButtonBuilder alloc] init]; + __block NSUInteger actionCount = 0; + + buttonBuilder.title(@"Save").actionBlock(^{ + actionCount += 1; + }); + alertBuilder.addButtonWithBuilder(buttonBuilder); + + XCTAssertNotNil(buttonBuilder.button); + [buttonBuilder.button sendActionsForControlEvents:UIControlEventTouchUpInside]; + XCTAssertEqual(actionCount, 1U); +} + +- (void)testTextFieldBuilderCreatesTextFieldAndExposesIt +{ + SCLAlertViewBuilder *alertBuilder = [[SCLAlertViewBuilder alloc] init]; + SCLALertViewTextFieldBuilder *textFieldBuilder = [[SCLALertViewTextFieldBuilder alloc] init]; + + textFieldBuilder.title(@"Email"); + alertBuilder.addTextFieldWithBuilder(textFieldBuilder); + + XCTAssertNotNil(textFieldBuilder.textField); + XCTAssertEqualObjects(textFieldBuilder.textField.placeholder, @"Email"); +} + +- (void)testShowBuilderStoresParametersAndCanShowAlert +{ + SCLAlertViewShowBuilder *showBuilder = [[SCLAlertViewShowBuilder alloc] init]; + UIViewController *viewController = [self presentingViewController]; + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + showBuilder.viewController(viewController) + .title(@"Hello") + .subTitle(@"World") + .style(SCLAlertViewStyleSuccess) + .closeButtonTitle(@"OK") + .duration(0.0); + [showBuilder showAlertView:alertView]; + + XCTAssertEqual(showBuilder.parameterViewController, viewController); + XCTAssertEqualObjects(showBuilder.parameterTitle, @"Hello"); + XCTAssertEqualObjects(alertView.labelTitle.text, @"Hello"); + XCTAssertEqualObjects(alertView.viewText.text, @"World"); + XCTAssertTrue([alertView isVisible]); + + [alertView hideView]; +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewButtonTests.m b/SCLAlertViewTests/SCLAlertViewButtonTests.m new file mode 100644 index 0000000..a5b5eb0 --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewButtonTests.m @@ -0,0 +1,117 @@ +// +// SCLAlertViewButtonTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" + +@interface SCLAlertViewButtonTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewButtonTests + +- (void)testButtonActionBlockRunsWhenTapped +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger actionCount = 0; + SCLButton *button = [alertView addButton:@"Run" actionBlock:^{ + actionCount += 1; + }]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(actionCount, 1U); +} + +- (void)testValidationBlockCanPreventAction +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger validationCount = 0; + __block NSUInteger actionCount = 0; + SCLButton *button = [alertView addButton:@"Save" validationBlock:^BOOL{ + validationCount += 1; + return NO; + } actionBlock:^{ + actionCount += 1; + }]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(validationCount, 1U); + XCTAssertEqual(actionCount, 0U); +} + +- (void)testValidationBlockAllowsAction +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger actionCount = 0; + SCLButton *button = [alertView addButton:@"Save" validationBlock:^BOOL{ + return YES; + } actionBlock:^{ + actionCount += 1; + }]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(actionCount, 1U); +} + +- (void)testSelectorButtonSendsActionToTarget +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + SCLAlertViewTestTarget *target = [[SCLAlertViewTestTarget alloc] init]; + SCLButton *button = [alertView addButton:@"Target" target:target selector:@selector(performAction)]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(target.actionCount, 1U); +} + +- (void)testButtonParseConfigAppliesSupportedKeys +{ + SCLButton *button = [[SCLButton alloc] initWithWindowWidth:240.0f]; + UIFont *font = [UIFont systemFontOfSize:19.0f weight:UIFontWeightBold]; + + [button parseConfig:@{ + @"backgroundColor": UIColor.blueColor, + @"textColor": UIColor.whiteColor, + @"cornerRadius": @7.0f, + @"borderWidth": @2.0f, + @"borderColor": UIColor.greenColor, + @"font": font + }]; + + XCTAssertEqualObjects(button.defaultBackgroundColor, UIColor.blueColor); + XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], UIColor.whiteColor); + XCTAssertEqualWithAccuracy(button.layer.cornerRadius, 7.0f, 0.001f); + XCTAssertEqualWithAccuracy(button.layer.borderWidth, 2.0f, 0.001f); + XCTAssertEqual(button.layer.borderColor, UIColor.greenColor.CGColor); + XCTAssertEqualObjects(button.titleLabel.font, font); +} + +- (void)testButtonHighlightUsesDarkerDefaultBackgroundColor +{ + SCLButton *button = [[SCLButton alloc] initWithWindowWidth:240.0f]; + button.defaultBackgroundColor = [UIColor colorWithRed:0.5f green:0.5f blue:0.5f alpha:1.0f]; + + button.highlighted = YES; + UIColor *highlightedColor = button.backgroundColor; + button.highlighted = NO; + + XCTAssertNotEqualObjects(highlightedColor, button.defaultBackgroundColor); + XCTAssertEqualObjects(button.backgroundColor, button.defaultBackgroundColor); +} + +- (void)testButtonWidthAdjustmentHandlesZeroButtons +{ + SCLButton *button = [[SCLButton alloc] initWithWindowWidth:240.0f]; + + XCTAssertNoThrow([button adjustWidthWithWindowWidth:240.0f numberOfButtons:0]); + XCTAssertEqualWithAccuracy(button.frame.size.width, 216.0f, 0.001f); + XCTAssertEqualWithAccuracy(button.frame.size.height, 35.0f, 0.001f); +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewComponentTests.m b/SCLAlertViewTests/SCLAlertViewComponentTests.m new file mode 100644 index 0000000..89cf16d --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewComponentTests.m @@ -0,0 +1,118 @@ +// +// SCLAlertViewComponentTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" +#import "SCLTextView.h" +#import "SCLSwitchView.h" + +@interface SCLAlertViewComponentTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewComponentTests + +- (void)testAddTextFieldConfiguresTextAndReturnKeys +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + SCLTextView *first = [alertView addTextField:@"Email" setDefaultText:@"a@example.com"]; + SCLTextView *second = [alertView addTextField:@"Password" setDefaultText:nil]; + + XCTAssertEqualObjects(first.placeholder, @"Email"); + XCTAssertEqualObjects(first.text, @"a@example.com"); + XCTAssertEqual((id)first.delegate, alertView); + XCTAssertEqual(first.returnKeyType, UIReturnKeyNext); + XCTAssertEqualObjects(second.placeholder, @"Password"); + XCTAssertEqual(second.returnKeyType, UIReturnKeyDone); +} + +- (void)testAddCustomTextFieldUpdatesPreviousReturnKey +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + UITextField *first = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + UITextField *second = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + + [alertView addCustomTextField:first]; + [alertView addCustomTextField:second]; + + XCTAssertEqual(first.returnKeyType, UIReturnKeyNext); + XCTAssertNotNil(first.superview); + XCTAssertNotNil(second.superview); +} + +- (void)testTextFieldReturnMovesFocusAndResignsLastField +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + SCLAlertViewTrackingTextField *first = [[SCLAlertViewTrackingTextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + SCLAlertViewTrackingTextField *second = [[SCLAlertViewTrackingTextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + [alertView addCustomTextField:first]; + [alertView addCustomTextField:second]; + + XCTAssertFalse([alertView textFieldShouldReturn:first]); + XCTAssertEqual(second.becomeFirstResponderCount, 1U); + + XCTAssertFalse([alertView textFieldShouldReturn:second]); + XCTAssertEqual(second.resignFirstResponderCount, 1U); +} + +- (void)testAddSwitchViewReturnsConfiguredSwitch +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + SCLSwitchView *switchView = [alertView addSwitchViewWithLabel:@"Remember me"]; + switchView.selected = YES; + switchView.tintColor = UIColor.redColor; + + XCTAssertEqualObjects(switchView.labelText, @"Remember me"); + XCTAssertTrue(switchView.isSelected); + XCTAssertEqualObjects(switchView.tintColor, UIColor.redColor); + XCTAssertNotNil(switchView.superview); +} + +- (void)testAddCustomViewReturnsSameAttachedView +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 80.0f, 25.0f)]; + + UIView *returnedView = [alertView addCustomView:customView]; + + XCTAssertEqual(returnedView, customView); + XCTAssertNotNil(customView.superview); +} + +- (void)testTextViewDefaultsAndSizing +{ + SCLTextView *textView = [[SCLTextView alloc] init]; + + XCTAssertEqual(textView.borderStyle, UITextBorderStyleRoundedRect); + XCTAssertEqual(textView.clearButtonMode, UITextFieldViewModeWhileEditing); + XCTAssertEqual(textView.returnKeyType, UIReturnKeyDone); + XCTAssertGreaterThanOrEqual(textView.frame.size.height, 35.0f); + XCTAssertGreaterThanOrEqual([textView intrinsicContentSize].height, 35.0f); + XCTAssertGreaterThanOrEqual([textView sizeThatFits:CGSizeMake(120.0f, 1.0f)].height, 35.0f); +} + +- (void)testSwitchViewPropertiesRoundTrip +{ + SCLSwitchView *switchView = [[SCLSwitchView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 40.0f)]; + UIFont *font = [UIFont systemFontOfSize:13.0f]; + + switchView.labelText = @"Enabled"; + switchView.labelColor = UIColor.purpleColor; + switchView.labelFont = font; + switchView.tintColor = UIColor.orangeColor; + switchView.selected = YES; + + XCTAssertEqualObjects(switchView.labelText, @"Enabled"); + XCTAssertEqualObjects(switchView.labelColor, UIColor.purpleColor); + XCTAssertEqualObjects(switchView.labelFont, font); + XCTAssertEqualObjects(switchView.tintColor, UIColor.orangeColor); + XCTAssertTrue(switchView.isSelected); + XCTAssertGreaterThan([switchView sizeThatFits:CGSizeMake(200.0f, 0.0f)].height, 0.0f); +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewPresentationTests.m b/SCLAlertViewTests/SCLAlertViewPresentationTests.m new file mode 100644 index 0000000..3b4f08b --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewPresentationTests.m @@ -0,0 +1,208 @@ +// +// SCLAlertViewPresentationTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" +#import "SCLAlertViewResponder.h" + +@interface SCLAlertViewPresentationTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewPresentationTests + +- (void)testDefaultInitializerConfiguresVisibleDefaults +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + XCTAssertNotNil(alertView.labelTitle); + XCTAssertNotNil(alertView.viewText); + XCTAssertEqual(alertView.showAnimationType, SCLAlertViewShowAnimationSlideInFromTop); + XCTAssertEqual(alertView.hideAnimationType, SCLAlertViewHideAnimationFadeOut); + XCTAssertEqual(alertView.backgroundType, SCLAlertViewBackgroundShadow); + XCTAssertTrue(alertView.tintTopCircle); + XCTAssertFalse(alertView.shouldDismissOnTapOutside); + XCTAssertNil(alertView.view.superview); +} + +- (void)testCustomWidthControlsInitialButtonWidth +{ + SCLAlertView *alertView = [[SCLAlertView alloc] initWithWidth:300.0f]; + + SCLButton *button = [alertView addButton:@"Continue" actionBlock:^{ + }]; + + XCTAssertEqualWithAccuracy(button.frame.size.width, 276.0f, 0.001f); +} + +- (void)testFontSettersApplyToExistingLabelsAndFutureButtons +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + [alertView setTitleFontFamily:@"HelveticaNeue-Bold" withSize:24.0f]; + [alertView setBodyTextFontFamily:@"HelveticaNeue-Italic" withSize:16.0f]; + [alertView setButtonsTextFontFamily:@"HelveticaNeue-Light" withSize:18.0f]; + SCLButton *button = [alertView addButton:@"OK" actionBlock:^{ + }]; + + XCTAssertEqualWithAccuracy(alertView.labelTitle.font.pointSize, 24.0f, 0.001f); + XCTAssertEqualObjects(alertView.labelTitle.font.fontName, @"HelveticaNeue-Bold"); + XCTAssertEqualWithAccuracy(alertView.viewText.font.pointSize, 16.0f, 0.001f); + XCTAssertEqualObjects(alertView.viewText.font.fontName, @"HelveticaNeue-Italic"); + XCTAssertEqualWithAccuracy(button.titleLabel.font.pointSize, 18.0f, 0.001f); +} + +- (void)testShowSuccessConfiguresTitleSubtitleVisibilityAndDismissCallback +{ + UIViewController *viewController = [self presentingViewController]; + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger dismissCount = 0; + [alertView alertIsDismissed:^{ + dismissCount += 1; + }]; + + [alertView showSuccess:viewController title:@"Saved" subTitle:@"Done" closeButtonTitle:@"OK" duration:0.0]; + + XCTAssertTrue([alertView isVisible]); + XCTAssertEqualObjects(alertView.labelTitle.text, @"Saved"); + XCTAssertEqualObjects(alertView.viewText.text, @"Done"); + XCTAssertEqual(alertView.parentViewController, viewController); + XCTAssertEqual([self buttonsInView:alertView.view].count, 1U); + + [alertView hideView]; + + XCTAssertEqual(dismissCount, 1U); +} + +- (void)testShowWithoutTitleRemovesTitleLabel +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + [alertView showInfo:[self presentingViewController] title:@" " subTitle:@"Body" closeButtonTitle:nil duration:0.0]; + + XCTAssertNil(alertView.labelTitle); + XCTAssertEqualObjects(alertView.viewText.text, @"Body"); + + [alertView hideView]; +} + +- (void)testShowWithoutSubtitleRemovesBodyText +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + [alertView showWarning:[self presentingViewController] title:@"Warning" subTitle:@"\n" closeButtonTitle:nil duration:0.0]; + + XCTAssertEqualObjects(alertView.labelTitle.text, @"Warning"); + XCTAssertNil(alertView.viewText); + + [alertView hideView]; +} + +- (void)testAttributedFormatBlockIsAppliedWhenShowingSubtitle +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + alertView.attributedFormatBlock = ^NSAttributedString *(NSString *value) { + return [[NSAttributedString alloc] initWithString:value attributes:@{ + NSForegroundColorAttributeName: UIColor.redColor + }]; + }; + + [alertView showNotice:[self presentingViewController] title:@"Notice" subTitle:@"Body" closeButtonTitle:nil duration:0.0]; + + UIColor *color = [alertView.viewText.attributedText attribute:NSForegroundColorAttributeName atIndex:0 effectiveRange:nil]; + XCTAssertEqualObjects(color, UIColor.redColor); + + [alertView hideView]; +} + +- (void)testButtonFormatBlockIsAppliedDuringShow +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + alertView.buttonFormatBlock = ^NSDictionary *{ + return @{ + @"backgroundColor": UIColor.blackColor, + @"textColor": UIColor.yellowColor, + @"borderWidth": @1.0f, + @"borderColor": UIColor.redColor + }; + }; + SCLButton *button = [alertView addButton:@"Custom" actionBlock:^{ + }]; + + [alertView showQuestion:[self presentingViewController] title:@"Question" subTitle:@"Body" closeButtonTitle:nil duration:0.0]; + + XCTAssertEqualObjects(button.defaultBackgroundColor, UIColor.blackColor); + XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], UIColor.yellowColor); + XCTAssertEqualWithAccuracy(button.layer.borderWidth, 1.0f, 0.001f); + XCTAssertEqual(button.layer.borderColor, UIColor.redColor.CGColor); + + [alertView hideView]; +} + +- (void)testCompleteButtonFormatBlockIsAppliedToCloseButton +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + alertView.completeButtonFormatBlock = ^NSDictionary *{ + return @{ + @"backgroundColor": UIColor.grayColor, + @"textColor": UIColor.whiteColor + }; + }; + + [alertView showError:[self presentingViewController] title:@"Error" subTitle:@"Body" closeButtonTitle:@"Close" duration:0.0]; + + SCLButton *button = [self buttonsInView:alertView.view].firstObject; + XCTAssertEqualObjects(button.defaultBackgroundColor, UIColor.grayColor); + XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], UIColor.whiteColor); + + [alertView hideView]; +} + +- (void)testButtonTimerClampsOutOfRangeIndex +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + [alertView addButton:@"OK" actionBlock:^{ + }]; + [alertView addTimerToButtonIndex:NSIntegerMax reverse:YES]; + + XCTAssertNoThrow([alertView showSuccess:[self presentingViewController] + title:@"Saved" + subTitle:@"Done" + closeButtonTitle:nil + duration:1.0]); + [alertView hideView]; +} + +- (void)testButtonTimerBeforeButtonsIsIgnored +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + XCTAssertNoThrow([alertView addTimerToButtonIndex:0 reverse:NO]); + XCTAssertNoThrow([alertView showSuccess:[self presentingViewController] + title:@"Saved" + subTitle:@"Done" + closeButtonTitle:nil + duration:1.0]); + [alertView hideView]; +} + +- (void)testResponderUpdatesAlertAndClosesIt +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + [alertView showSuccess:[self presentingViewController] title:@"Old" subTitle:@"Old body" closeButtonTitle:nil duration:0.0]; + SCLAlertViewResponder *responder = [[SCLAlertViewResponder alloc] init:alertView]; + + [responder setTitle:@"New"]; + [responder setSubTitle:@"New body"]; + + XCTAssertEqualObjects(alertView.labelTitle.text, @"New"); + XCTAssertEqualObjects(alertView.viewText.text, @"New body"); + + [responder close]; + XCTAssertFalse([alertView isVisible]); +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewTestHelpers.h b/SCLAlertViewTests/SCLAlertViewTestHelpers.h new file mode 100644 index 0000000..1d20d0e --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewTestHelpers.h @@ -0,0 +1,30 @@ +// +// SCLAlertViewTestHelpers.h +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import +#import +#import "SCLAlertView.h" +#import "SCLButton.h" + +@interface SCLAlertView (Tests) +@end + +@interface SCLAlertViewTestCase : XCTestCase +- (UIViewController *)presentingViewController; +- (NSArray *)buttonsInView:(UIView *)view; +@end + +@interface SCLAlertViewTestTarget : NSObject +@property (nonatomic) NSUInteger actionCount; +- (void)performAction; +@end + +@interface SCLAlertViewTrackingTextField : UITextField +@property (nonatomic) NSUInteger becomeFirstResponderCount; +@property (nonatomic) NSUInteger resignFirstResponderCount; +@end diff --git a/SCLAlertViewTests/SCLAlertViewTestHelpers.m b/SCLAlertViewTests/SCLAlertViewTestHelpers.m new file mode 100644 index 0000000..32f1727 --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewTestHelpers.m @@ -0,0 +1,73 @@ +// +// SCLAlertViewTestHelpers.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" + +@implementation SCLAlertViewTestCase +{ + BOOL _animationsWereEnabled; +} + +- (void)setUp +{ + [super setUp]; + _animationsWereEnabled = UIView.areAnimationsEnabled; + [UIView setAnimationsEnabled:NO]; +} + +- (void)tearDown +{ + [UIView setAnimationsEnabled:_animationsWereEnabled]; + [super tearDown]; +} + +- (UIViewController *)presentingViewController +{ + UIViewController *viewController = [[UIViewController alloc] init]; + viewController.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f); + return viewController; +} + +- (NSArray *)buttonsInView:(UIView *)view +{ + NSMutableArray *buttons = [NSMutableArray array]; + if ([view isKindOfClass:SCLButton.class]) { + [buttons addObject:(SCLButton *)view]; + } + for (UIView *subview in view.subviews) { + [buttons addObjectsFromArray:[self buttonsInView:subview]]; + } + return buttons; +} + +@end + +@implementation SCLAlertViewTestTarget + +- (void)performAction +{ + self.actionCount += 1; +} + +@end + +@implementation SCLAlertViewTrackingTextField + +- (BOOL)becomeFirstResponder +{ + self.becomeFirstResponderCount += 1; + return YES; +} + +- (BOOL)resignFirstResponder +{ + self.resignFirstResponderCount += 1; + return YES; +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewTests.m b/SCLAlertViewTests/SCLAlertViewTests.m deleted file mode 100644 index 8b06453..0000000 --- a/SCLAlertViewTests/SCLAlertViewTests.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// SCLAlertViewTests.m -// SCLAlertViewTests -// -// Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. -// - -#import -#import - -@interface SCLAlertViewTests : XCTestCase - -@end - -@implementation SCLAlertViewTests - -- (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testExample { - // This is an example of a functional test case. - XCTAssert(YES, @"Pass"); -} - -- (void)testPerformanceExample { - // This is an example of a performance test case. - [self measureBlock:^{ - // Put the code you want to measure the time of here. - }]; -} - -@end diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..b0964ab --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +ruby = "3.3.0"